Add CanvasKit bindings for RuntimeShader.MakeTraced.

To save space, debug trace bindings can be disabled by turning off
SK_INCLUDE_SKSL_TRACE. Most clients shouldn't need them.

Change-Id: Ifadc05b3eeed95def334fa7e0755f61caeef27f0
Bug: skia:12818
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/494244
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Kevin Lubick <kjlubick@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
This commit is contained in:
John Stiles 2022-01-12 17:15:31 -05:00 committed by SkCQ
parent a379b7d4a3
commit 575d0c5e1d
5 changed files with 113 additions and 7 deletions

View File

@ -71,7 +71,7 @@ npm:
# These features are turned off to keep code size smaller for the
# general use case.
./compile.sh release no_skottie no_particles no_rt_shader no_alias_font no_effects_deserialization
./compile.sh release no_skottie no_particles no_rt_shader no_sksl_trace no_alias_font no_effects_deserialization
cp ../../out/canvaskit_wasm/canvaskit.js ./npm_build/bin
cp ../../out/canvaskit_wasm/canvaskit.wasm ./npm_build/bin

View File

@ -85,6 +85,10 @@
#include "include/pathops/SkPathOps.h"
#endif
#if defined(SK_INCLUDE_RUNTIME_EFFECT) && defined(SK_INCLUDE_SKSL_TRACE)
#include "include/sksl/SkSLDebugTrace.h"
#endif
#ifndef SK_NO_FONTS
sk_sp<SkFontMgr> SkFontMgr_New_Custom_Data(sk_sp<SkData>* datas, int n);
#endif
@ -1772,6 +1776,21 @@ EMSCRIPTEN_BINDINGS(Skia) {
}), allow_raw_pointers());
#ifdef SK_INCLUDE_RUNTIME_EFFECT
#ifdef SK_INCLUDE_SKSL_TRACE
class_<SkSL::DebugTrace>("DebugTrace")
.smart_ptr<sk_sp<SkSL::DebugTrace>>("sk_sp<DebugTrace>")
.function("writeTrace", optional_override([](SkSL::DebugTrace& self) -> std::string {
SkDynamicMemoryWStream wstream;
self.writeTrace(&wstream);
sk_sp<SkData> trace = wstream.detachAsData();
return std::string(reinterpret_cast<const char*>(trace->bytes()), trace->size());
}));
value_object<SkRuntimeEffect::TracedShader>("TracedShader")
.field("shader", &SkRuntimeEffect::TracedShader::shader)
.field("debugTrace", &SkRuntimeEffect::TracedShader::debugTrace);
#endif
class_<SkRuntimeEffect>("RuntimeEffect")
.smart_ptr<sk_sp<SkRuntimeEffect>>("sk_sp<RuntimeEffect>")
.class_function("_Make", optional_override([](std::string sksl,
@ -1785,6 +1804,14 @@ EMSCRIPTEN_BINDINGS(Skia) {
}
return effect;
}))
#ifdef SK_INCLUDE_SKSL_TRACE
.class_function("MakeTraced", optional_override([](
sk_sp<SkShader> shader,
int traceCoordX,
int traceCoordY) -> SkRuntimeEffect::TracedShader {
return SkRuntimeEffect::MakeTraced(shader, SkIPoint::Make(traceCoordX, traceCoordY));
}))
#endif
.function("_makeShader", optional_override([](SkRuntimeEffect& self, WASMPointerF32 fPtr, size_t fLen, bool isOpaque,
WASMPointerF32 mPtr)->sk_sp<SkShader> {
void* inputData = reinterpret_cast<void*>(fPtr);

View File

@ -153,6 +153,11 @@ if [[ $@ == *no_rt_shader* ]] ; then
RT_SHADER_JS=""
fi
WASM_SKSL_TRACE="-DSK_INCLUDE_SKSL_TRACE"
if [[ $@ == *no_sksl_trace* ]] ; then
WASM_SKSL_TRACE=""
fi
MATRIX_HELPER_JS="--pre-js $BASE_DIR/matrix.js"
if [[ $@ == *no_matrix* ]]; then
echo "Omitting matrix helper code"
@ -363,6 +368,7 @@ EMCC_DEBUG=1 ${EMCXX} \
$WASM_GPU \
$WASM_PATHOPS \
$WASM_RT_SHADER \
$WASM_SKSL_TRACE \
$WASM_SKP \
$FONT_CFLAGS \
-std=c++17 \

View File

@ -407,7 +407,7 @@ export interface CanvasKit {
readonly PictureRecorder: DefaultConstructor<PictureRecorder>;
readonly TextStyle: TextStyleConstructor;
// Factories, i.e. things made with CanvasKit.Foo.MakeTurboEncapsulator()
// Factories, i.e. things made with CanvasKit.Foo.MakeTurboEncabulator()
readonly ParagraphBuilder: ParagraphBuilderFactory;
readonly ColorFilter: ColorFilterFactory;
readonly FontMgr: FontMgrFactory;
@ -3332,6 +3332,15 @@ export interface PathEffectFactory {
/**
* See RuntimeEffect.h for more details.
*/
export interface DebugTrace extends EmbindObject<DebugTrace> {
writeTrace(): string;
}
export interface TracedShader {
shader: RuntimeEffect;
debugTrace: DebugTrace;
}
export interface RuntimeEffectFactory {
/**
* Compiles a RuntimeEffect from the given shader code.
@ -3340,6 +3349,14 @@ export interface RuntimeEffectFactory {
* be printed to console.log().
*/
Make(sksl: string, callback?: (err: string) => void): RuntimeEffect | null;
/**
* Adds debug tracing to an existing RuntimeEffect.
* @param shader - An already-assembled shader, created with RuntimeEffect.makeShader.
* @param traceCoordX - the X coordinate of the device-space pixel to trace
* @param traceCoordY - the Y coordinate of the device-space pixel to trace
*/
MakeTraced(shader: RuntimeEffect, traceCoordX: number, traceCoordY: number): TracedShader;
}
/**

View File

@ -14,8 +14,6 @@ describe('Runtime shader effects', () => {
document.body.removeChild(container);
});
// On the SW backend, atan is not supported - a shader is returned, but
// it will draw blank.
const spiralSkSL = `
uniform float rad_scale;
uniform int2 in_center;
@ -96,6 +94,64 @@ half4 main(float2 p) {
expect(error).toContain('error');
});
it('can generate a debug trace', () => {
// We don't support debug tracing on GPU, so we always request a software canvas here.
const surface = CanvasKit.MakeSWCanvasSurface('test');
expect(surface).toBeTruthy('Could not make surface');
if (!surface) {
return;
}
const spiral = CanvasKit.RuntimeEffect.Make(spiralSkSL);
expect(spiral).toBeTruthy('could not compile program');
const canvas = surface.getCanvas();
const paint = new CanvasKit.Paint();
const shader = spiral.makeShader([
0.3,
CANVAS_WIDTH/2, CANVAS_HEIGHT/2,
1, 0, 0, 1, // solid red
0, 1, 0, 1], // solid green
true /*=opaque*/);
const traced = CanvasKit.RuntimeEffect.MakeTraced(shader, CANVAS_WIDTH/2, CANVAS_HEIGHT/2);
paint.setShader(traced.shader);
canvas.drawRect(CanvasKit.LTRBRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), paint);
const traceData = traced.debugTrace.writeTrace();
paint.delete();
shader.delete();
spiral.delete();
traced.shader.delete();
traced.debugTrace.delete();
surface.delete();
const parsedTrace = JSON.parse(traceData);
expect(parsedTrace).toBeTruthy('could not parse trace JSON');
expect(parsedTrace.functions).toBeTruthy('debug trace does not include function list');
expect(parsedTrace.slots).toBeTruthy('debug trace does not include slot list');
expect(parsedTrace.trace).toBeTruthy('debug trace does not include trace data');
expect(parsedTrace.nonsense).toBeFalsy('debug trace includes a nonsense key');
expect(parsedTrace.mystery).toBeFalsy('debug trace includes a mystery key');
expect(parsedTrace.source).toEqual([
"",
"uniform float rad_scale;",
"uniform int2 in_center;",
"uniform float4 in_colors0;",
"uniform float4 in_colors1;",
"",
"half4 main(float2 p) {",
" float2 pp = p - float2(in_center);",
" float radius = sqrt(dot(pp, pp));",
" radius = sqrt(radius);",
" float angle = atan(pp.y / pp.x);",
" float t = (angle + 3.1415926/2) / (3.1415926);",
" t += radius * rad_scale;",
" t = fract(t);",
" return half4(mix(in_colors0, in_colors1, t));",
"}"
]);
});
const loadBrick = fetch(
'/assets/brickwork-texture.jpg')
.then((response) => response.arrayBuffer());