[canvaskit] Add error callback for runtime effect constructor

It would otherwise be difficult/tedious/not-backwards-compatible
to return the RuntimeEffect AND the error message.

Change-Id: I9bdbafb653398ccbb72e6e762ec4b6af294f9110
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/365483
Reviewed-by: Joe Gregorio <jcgregorio@google.com>
This commit is contained in:
Kevin Lubick 2021-02-03 11:26:12 -05:00
parent 1db274d0b9
commit 70b6729a05
7 changed files with 43 additions and 6 deletions

View File

@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `getShadowLocalBounds()` to estimate the bounds of the shadows drawn by `Canvas.drawShadow`.
- compile.sh now takes "no_matrix", which will omit the helper JS to deal with 3x3, 4x4 and
SkColorMatrix (in case clients have logic to deal with that themselves).
- `CanvasKit.RuntimeEffect.Make` now takes an optional callback function that will be called
with any compilation error.
### Breaking
- `MakeImprovedNoise` is removed.

View File

@ -656,6 +656,9 @@ function rectangleTests(CK: CanvasKit) {
function runtimeEffectTests(CK: CanvasKit) {
const rt = CK.RuntimeEffect.Make('not real sksl code'); // $ExpectType RuntimeEffect | null
if (!rt) return;
const rt2 = CK.RuntimeEffect.Make('not real sksl code', (err) => {
console.log(err);
});
const someMatr = CK.Matrix.translated(2, 60);
const s1 = rt.makeShader([0, 1]); // $ExpectType Shader
const s2 = rt.makeShader([0, 1], true, someMatr); // $ExpectType Shader

View File

@ -3101,8 +3101,10 @@ export interface RuntimeEffectFactory {
/**
* Compiles a RuntimeEffect from the given shader code.
* @param sksl - Source code for a shader written in SkSL
* @param callback - will be called with any compilation error. If not provided, errors will
* be printed to console.log().
*/
Make(sksl: string): RuntimeEffect | null;
Make(sksl: string, callback?: (err: string) => void): RuntimeEffect | null;
}
/**

View File

@ -1674,11 +1674,13 @@ EMSCRIPTEN_BINDINGS(Skia) {
#ifdef SK_INCLUDE_RUNTIME_EFFECT
class_<SkRuntimeEffect>("RuntimeEffect")
.smart_ptr<sk_sp<SkRuntimeEffect>>("sk_sp<RuntimeEffect>")
.class_function("Make", optional_override([](std::string sksl)->sk_sp<SkRuntimeEffect> {
.class_function("_Make", optional_override([](std::string sksl,
emscripten::val errHandler
)->sk_sp<SkRuntimeEffect> {
SkString s(sksl.c_str(), sksl.length());
auto [effect, errorText] = SkRuntimeEffect::Make(s);
if (!effect) {
SkDebugf("Runtime effect failed to compile:\n%s\n", errorText.c_str());
errHandler.call<void>("onError", val(errorText.c_str()));
return nullptr;
}
return effect;

View File

@ -166,10 +166,14 @@ var CanvasKit = {
},
RuntimeEffect: {
// public API (from C++ bindings)
// public API (from JS bindings)
Make: function() {},
// private API
prototype: {
makeShader: function() {},
makeShaderWithChildren: function() {},
},
// private API (from C++ bindings)
_Make: function() {},
_makeShader: function() {},
_makeShaderWithChildren: function() {},
},

View File

@ -1,5 +1,20 @@
CanvasKit._extraInitializations = CanvasKit._extraInitializations || [];
CanvasKit._extraInitializations.push(function() {
// sksl is the shader code.
// errorCallback is a function that will be called with an error string if the
// effect cannot be made. If not provided, the error will be logged.
CanvasKit.RuntimeEffect.Make = function(sksl, errorCallback) {
// The easiest way to pass a function into C++ code is to wrap it in an object and
// treat it as an emscripten::val on the other side.
var callbackObj = {
'onError': errorCallback || function(err) {
console.log('RuntimeEffect error', err);
},
};
return CanvasKit.RuntimeEffect._Make(sksl, callbackObj);
};
CanvasKit.RuntimeEffect.prototype.makeShader = function(floats, isOpaque, localMatrix) {
// We don't need to free these floats because they will become owned by the shader.
var fptr = copy1dArray(floats, "HEAPF32");

View File

@ -70,6 +70,15 @@ half4 main(float2 p) {
testRTShader('rtshader_spiral_translated', done, CanvasKit.Matrix.translated(-200, 100));
});
it('can provide a error handler for compilation errors', () => {
let error = '';
const spiral = CanvasKit.RuntimeEffect.Make(`invalid sksl code, I hope`, (e) => {
error = e;
});
expect(spiral).toBeFalsy();
expect(error).toContain('error');
});
const loadBrick = fetch(
'/assets/brickwork-texture.jpg')
.then((response) => response.arrayBuffer());