xref: /aosp_15_r20/external/skia/modules/canvaskit/tests/rtshader_test.js (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Workerdescribe('Runtime shader effects', () => {
2*c8dee2aaSAndroid Build Coastguard Worker    let container;
3*c8dee2aaSAndroid Build Coastguard Worker
4*c8dee2aaSAndroid Build Coastguard Worker    beforeEach(async () => {
5*c8dee2aaSAndroid Build Coastguard Worker        await EverythingLoaded;
6*c8dee2aaSAndroid Build Coastguard Worker        container = document.createElement('div');
7*c8dee2aaSAndroid Build Coastguard Worker        container.innerHTML = `
8*c8dee2aaSAndroid Build Coastguard Worker            <canvas width=600 height=600 id=test></canvas>
9*c8dee2aaSAndroid Build Coastguard Worker            <canvas width=600 height=600 id=report></canvas>`;
10*c8dee2aaSAndroid Build Coastguard Worker        document.body.appendChild(container);
11*c8dee2aaSAndroid Build Coastguard Worker    });
12*c8dee2aaSAndroid Build Coastguard Worker
13*c8dee2aaSAndroid Build Coastguard Worker    afterEach(() => {
14*c8dee2aaSAndroid Build Coastguard Worker        document.body.removeChild(container);
15*c8dee2aaSAndroid Build Coastguard Worker    });
16*c8dee2aaSAndroid Build Coastguard Worker
17*c8dee2aaSAndroid Build Coastguard Worker    const spiralSkSL = `
18*c8dee2aaSAndroid Build Coastguard Workeruniform float rad_scale;
19*c8dee2aaSAndroid Build Coastguard Workeruniform int2   in_center;
20*c8dee2aaSAndroid Build Coastguard Workeruniform float4 in_colors0;
21*c8dee2aaSAndroid Build Coastguard Workeruniform float4 in_colors1;
22*c8dee2aaSAndroid Build Coastguard Worker
23*c8dee2aaSAndroid Build Coastguard Workerhalf4 main(float2 p) {
24*c8dee2aaSAndroid Build Coastguard Worker    float2 pp = p - float2(in_center);
25*c8dee2aaSAndroid Build Coastguard Worker    float radius = sqrt(dot(pp, pp));
26*c8dee2aaSAndroid Build Coastguard Worker    radius = sqrt(radius);
27*c8dee2aaSAndroid Build Coastguard Worker    float angle = atan(pp.y / pp.x);
28*c8dee2aaSAndroid Build Coastguard Worker    float t = (angle + 3.1415926/2) / (3.1415926);
29*c8dee2aaSAndroid Build Coastguard Worker    t += radius * rad_scale;
30*c8dee2aaSAndroid Build Coastguard Worker    t = fract(t);
31*c8dee2aaSAndroid Build Coastguard Worker    return half4(mix(in_colors0, in_colors1, t));
32*c8dee2aaSAndroid Build Coastguard Worker}`;
33*c8dee2aaSAndroid Build Coastguard Worker
34*c8dee2aaSAndroid Build Coastguard Worker    // TODO(kjlubick) rewrite testRTShader and callers to use gm.
35*c8dee2aaSAndroid Build Coastguard Worker    const testRTShader = (name, done, localMatrix) => {
36*c8dee2aaSAndroid Build Coastguard Worker        const surface = CanvasKit.MakeCanvasSurface('test');
37*c8dee2aaSAndroid Build Coastguard Worker        expect(surface).toBeTruthy('Could not make surface');
38*c8dee2aaSAndroid Build Coastguard Worker        if (!surface) {
39*c8dee2aaSAndroid Build Coastguard Worker            return;
40*c8dee2aaSAndroid Build Coastguard Worker        }
41*c8dee2aaSAndroid Build Coastguard Worker        const spiral = CanvasKit.RuntimeEffect.Make(spiralSkSL);
42*c8dee2aaSAndroid Build Coastguard Worker        expect(spiral).toBeTruthy('could not compile program');
43*c8dee2aaSAndroid Build Coastguard Worker
44*c8dee2aaSAndroid Build Coastguard Worker        expect(spiral.getUniformCount()     ).toEqual(4);
45*c8dee2aaSAndroid Build Coastguard Worker        expect(spiral.getUniformFloatCount()).toEqual(11);
46*c8dee2aaSAndroid Build Coastguard Worker        const center = spiral.getUniform(1);
47*c8dee2aaSAndroid Build Coastguard Worker        expect(center).toBeTruthy('could not fetch numbered uniform');
48*c8dee2aaSAndroid Build Coastguard Worker        expect(center.slot     ).toEqual(1);
49*c8dee2aaSAndroid Build Coastguard Worker        expect(center.columns  ).toEqual(2);
50*c8dee2aaSAndroid Build Coastguard Worker        expect(center.rows     ).toEqual(1);
51*c8dee2aaSAndroid Build Coastguard Worker        expect(center.isInteger).toEqual(true);
52*c8dee2aaSAndroid Build Coastguard Worker        const color_0 = spiral.getUniform(2);
53*c8dee2aaSAndroid Build Coastguard Worker        expect(color_0).toBeTruthy('could not fetch numbered uniform');
54*c8dee2aaSAndroid Build Coastguard Worker        expect(color_0.slot     ).toEqual(3);
55*c8dee2aaSAndroid Build Coastguard Worker        expect(color_0.columns  ).toEqual(4);
56*c8dee2aaSAndroid Build Coastguard Worker        expect(color_0.rows     ).toEqual(1);
57*c8dee2aaSAndroid Build Coastguard Worker        expect(color_0.isInteger).toEqual(false);
58*c8dee2aaSAndroid Build Coastguard Worker        expect(spiral.getUniformName(2)).toEqual('in_colors0');
59*c8dee2aaSAndroid Build Coastguard Worker
60*c8dee2aaSAndroid Build Coastguard Worker        const canvas = surface.getCanvas();
61*c8dee2aaSAndroid Build Coastguard Worker        const paint = new CanvasKit.Paint();
62*c8dee2aaSAndroid Build Coastguard Worker        canvas.clear(CanvasKit.BLACK); // black should not be visible
63*c8dee2aaSAndroid Build Coastguard Worker        const shader = spiral.makeShader([
64*c8dee2aaSAndroid Build Coastguard Worker            0.3,
65*c8dee2aaSAndroid Build Coastguard Worker            CANVAS_WIDTH/2, CANVAS_HEIGHT/2,
66*c8dee2aaSAndroid Build Coastguard Worker            1, 0, 0, 1, // solid red
67*c8dee2aaSAndroid Build Coastguard Worker            0, 1, 0, 1], // solid green
68*c8dee2aaSAndroid Build Coastguard Worker            localMatrix);
69*c8dee2aaSAndroid Build Coastguard Worker        paint.setShader(shader);
70*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawRect(CanvasKit.LTRBRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), paint);
71*c8dee2aaSAndroid Build Coastguard Worker
72*c8dee2aaSAndroid Build Coastguard Worker        paint.delete();
73*c8dee2aaSAndroid Build Coastguard Worker        shader.delete();
74*c8dee2aaSAndroid Build Coastguard Worker        spiral.delete();
75*c8dee2aaSAndroid Build Coastguard Worker
76*c8dee2aaSAndroid Build Coastguard Worker        reportSurface(surface, name, done);
77*c8dee2aaSAndroid Build Coastguard Worker    };
78*c8dee2aaSAndroid Build Coastguard Worker
79*c8dee2aaSAndroid Build Coastguard Worker    it('can compile custom shader code', (done) => {
80*c8dee2aaSAndroid Build Coastguard Worker        testRTShader('rtshader_spiral', done);
81*c8dee2aaSAndroid Build Coastguard Worker    });
82*c8dee2aaSAndroid Build Coastguard Worker
83*c8dee2aaSAndroid Build Coastguard Worker    it('can apply a matrix to the shader', (done) => {
84*c8dee2aaSAndroid Build Coastguard Worker        testRTShader('rtshader_spiral_translated', done, CanvasKit.Matrix.translated(-200, 100));
85*c8dee2aaSAndroid Build Coastguard Worker    });
86*c8dee2aaSAndroid Build Coastguard Worker
87*c8dee2aaSAndroid Build Coastguard Worker    it('can provide a error handler for compilation errors', () => {
88*c8dee2aaSAndroid Build Coastguard Worker        let error = '';
89*c8dee2aaSAndroid Build Coastguard Worker        const spiral = CanvasKit.RuntimeEffect.Make(`invalid sksl code, I hope`, (e) => {
90*c8dee2aaSAndroid Build Coastguard Worker            error = e;
91*c8dee2aaSAndroid Build Coastguard Worker        });
92*c8dee2aaSAndroid Build Coastguard Worker        expect(spiral).toBeFalsy();
93*c8dee2aaSAndroid Build Coastguard Worker        expect(error).toContain('error');
94*c8dee2aaSAndroid Build Coastguard Worker    });
95*c8dee2aaSAndroid Build Coastguard Worker
96*c8dee2aaSAndroid Build Coastguard Worker    it('can generate a debug trace', () => {
97*c8dee2aaSAndroid Build Coastguard Worker        // We don't support debug tracing on GPU, so we always request a software canvas here.
98*c8dee2aaSAndroid Build Coastguard Worker        const surface = CanvasKit.MakeSWCanvasSurface('test');
99*c8dee2aaSAndroid Build Coastguard Worker        expect(surface).toBeTruthy('Could not make surface');
100*c8dee2aaSAndroid Build Coastguard Worker        if (!surface) {
101*c8dee2aaSAndroid Build Coastguard Worker            return;
102*c8dee2aaSAndroid Build Coastguard Worker        }
103*c8dee2aaSAndroid Build Coastguard Worker        const spiral = CanvasKit.RuntimeEffect.Make(spiralSkSL);
104*c8dee2aaSAndroid Build Coastguard Worker        expect(spiral).toBeTruthy('could not compile program');
105*c8dee2aaSAndroid Build Coastguard Worker
106*c8dee2aaSAndroid Build Coastguard Worker        const canvas = surface.getCanvas();
107*c8dee2aaSAndroid Build Coastguard Worker        const paint = new CanvasKit.Paint();
108*c8dee2aaSAndroid Build Coastguard Worker        const shader = spiral.makeShader([
109*c8dee2aaSAndroid Build Coastguard Worker            0.3,
110*c8dee2aaSAndroid Build Coastguard Worker            CANVAS_WIDTH/2, CANVAS_HEIGHT/2,
111*c8dee2aaSAndroid Build Coastguard Worker            1, 0, 0, 1,   // solid red
112*c8dee2aaSAndroid Build Coastguard Worker            0, 1, 0, 1]); // solid green
113*c8dee2aaSAndroid Build Coastguard Worker
114*c8dee2aaSAndroid Build Coastguard Worker        const traced = CanvasKit.RuntimeEffect.MakeTraced(shader, CANVAS_WIDTH/2, CANVAS_HEIGHT/2);
115*c8dee2aaSAndroid Build Coastguard Worker        paint.setShader(traced.shader);
116*c8dee2aaSAndroid Build Coastguard Worker        canvas.drawRect(CanvasKit.LTRBRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), paint);
117*c8dee2aaSAndroid Build Coastguard Worker
118*c8dee2aaSAndroid Build Coastguard Worker        const traceData = traced.debugTrace.writeTrace();
119*c8dee2aaSAndroid Build Coastguard Worker        paint.delete();
120*c8dee2aaSAndroid Build Coastguard Worker        shader.delete();
121*c8dee2aaSAndroid Build Coastguard Worker        spiral.delete();
122*c8dee2aaSAndroid Build Coastguard Worker        traced.shader.delete();
123*c8dee2aaSAndroid Build Coastguard Worker        traced.debugTrace.delete();
124*c8dee2aaSAndroid Build Coastguard Worker        surface.delete();
125*c8dee2aaSAndroid Build Coastguard Worker
126*c8dee2aaSAndroid Build Coastguard Worker        const parsedTrace = JSON.parse(traceData);
127*c8dee2aaSAndroid Build Coastguard Worker        expect(parsedTrace).toBeTruthy('could not parse trace JSON');
128*c8dee2aaSAndroid Build Coastguard Worker        expect(parsedTrace.functions).toBeTruthy('debug trace does not include function list');
129*c8dee2aaSAndroid Build Coastguard Worker        expect(parsedTrace.slots).toBeTruthy('debug trace does not include slot list');
130*c8dee2aaSAndroid Build Coastguard Worker        expect(parsedTrace.trace).toBeTruthy('debug trace does not include trace data');
131*c8dee2aaSAndroid Build Coastguard Worker        expect(parsedTrace.nonsense).toBeFalsy('debug trace includes a nonsense key');
132*c8dee2aaSAndroid Build Coastguard Worker        expect(parsedTrace.mystery).toBeFalsy('debug trace includes a mystery key');
133*c8dee2aaSAndroid Build Coastguard Worker        expect(parsedTrace.source).toEqual([
134*c8dee2aaSAndroid Build Coastguard Worker            "",
135*c8dee2aaSAndroid Build Coastguard Worker            "uniform float rad_scale;",
136*c8dee2aaSAndroid Build Coastguard Worker            "uniform int2   in_center;",
137*c8dee2aaSAndroid Build Coastguard Worker            "uniform float4 in_colors0;",
138*c8dee2aaSAndroid Build Coastguard Worker            "uniform float4 in_colors1;",
139*c8dee2aaSAndroid Build Coastguard Worker            "",
140*c8dee2aaSAndroid Build Coastguard Worker            "half4 main(float2 p) {",
141*c8dee2aaSAndroid Build Coastguard Worker            "    float2 pp = p - float2(in_center);",
142*c8dee2aaSAndroid Build Coastguard Worker            "    float radius = sqrt(dot(pp, pp));",
143*c8dee2aaSAndroid Build Coastguard Worker            "    radius = sqrt(radius);",
144*c8dee2aaSAndroid Build Coastguard Worker            "    float angle = atan(pp.y / pp.x);",
145*c8dee2aaSAndroid Build Coastguard Worker            "    float t = (angle + 3.1415926/2) / (3.1415926);",
146*c8dee2aaSAndroid Build Coastguard Worker            "    t += radius * rad_scale;",
147*c8dee2aaSAndroid Build Coastguard Worker            "    t = fract(t);",
148*c8dee2aaSAndroid Build Coastguard Worker            "    return half4(mix(in_colors0, in_colors1, t));",
149*c8dee2aaSAndroid Build Coastguard Worker            "}"
150*c8dee2aaSAndroid Build Coastguard Worker        ]);
151*c8dee2aaSAndroid Build Coastguard Worker    });
152*c8dee2aaSAndroid Build Coastguard Worker
153*c8dee2aaSAndroid Build Coastguard Worker    const loadBrick = fetch(
154*c8dee2aaSAndroid Build Coastguard Worker        '/assets/brickwork-texture.jpg')
155*c8dee2aaSAndroid Build Coastguard Worker        .then((response) => response.arrayBuffer());
156*c8dee2aaSAndroid Build Coastguard Worker    const loadMandrill = fetch(
157*c8dee2aaSAndroid Build Coastguard Worker        '/assets/mandrill_512.png')
158*c8dee2aaSAndroid Build Coastguard Worker        .then((response) => response.arrayBuffer());
159*c8dee2aaSAndroid Build Coastguard Worker
160*c8dee2aaSAndroid Build Coastguard Worker    const thresholdSkSL = `
161*c8dee2aaSAndroid Build Coastguard Workeruniform shader before_map;
162*c8dee2aaSAndroid Build Coastguard Workeruniform shader after_map;
163*c8dee2aaSAndroid Build Coastguard Workeruniform shader threshold_map;
164*c8dee2aaSAndroid Build Coastguard Worker
165*c8dee2aaSAndroid Build Coastguard Workeruniform float cutoff;
166*c8dee2aaSAndroid Build Coastguard Workeruniform float slope;
167*c8dee2aaSAndroid Build Coastguard Worker
168*c8dee2aaSAndroid Build Coastguard Workerfloat smooth_cutoff(float x) {
169*c8dee2aaSAndroid Build Coastguard Worker    x = x * slope + (0.5 - slope * cutoff);
170*c8dee2aaSAndroid Build Coastguard Worker    return clamp(x, 0, 1);
171*c8dee2aaSAndroid Build Coastguard Worker}
172*c8dee2aaSAndroid Build Coastguard Worker
173*c8dee2aaSAndroid Build Coastguard Workerhalf4 main(float2 xy) {
174*c8dee2aaSAndroid Build Coastguard Worker    half4 before = before_map.eval(xy);
175*c8dee2aaSAndroid Build Coastguard Worker    half4 after = after_map.eval(xy);
176*c8dee2aaSAndroid Build Coastguard Worker
177*c8dee2aaSAndroid Build Coastguard Worker    float m = smooth_cutoff(threshold_map.eval(xy).r);
178*c8dee2aaSAndroid Build Coastguard Worker    return mix(before, after, half(m));
179*c8dee2aaSAndroid Build Coastguard Worker}`;
180*c8dee2aaSAndroid Build Coastguard Worker
181*c8dee2aaSAndroid Build Coastguard Worker    // TODO(kjlubick) rewrite testChildrenShader and callers to use gm.
182*c8dee2aaSAndroid Build Coastguard Worker    const testChildrenShader = (name, done, localMatrix) => {
183*c8dee2aaSAndroid Build Coastguard Worker        Promise.all([loadBrick, loadMandrill]).then((values) => {
184*c8dee2aaSAndroid Build Coastguard Worker            catchException(done, () => {
185*c8dee2aaSAndroid Build Coastguard Worker                const [brickData, mandrillData] = values;
186*c8dee2aaSAndroid Build Coastguard Worker                const brickImg = CanvasKit.MakeImageFromEncoded(brickData);
187*c8dee2aaSAndroid Build Coastguard Worker                expect(brickImg).toBeTruthy('brick image could not be loaded');
188*c8dee2aaSAndroid Build Coastguard Worker                const mandrillImg = CanvasKit.MakeImageFromEncoded(mandrillData);
189*c8dee2aaSAndroid Build Coastguard Worker                expect(mandrillImg).toBeTruthy('mandrill image could not be loaded');
190*c8dee2aaSAndroid Build Coastguard Worker
191*c8dee2aaSAndroid Build Coastguard Worker                const thresholdEffect = CanvasKit.RuntimeEffect.Make(thresholdSkSL);
192*c8dee2aaSAndroid Build Coastguard Worker                expect(thresholdEffect).toBeTruthy('threshold did not compile');
193*c8dee2aaSAndroid Build Coastguard Worker                const spiralEffect = CanvasKit.RuntimeEffect.Make(spiralSkSL);
194*c8dee2aaSAndroid Build Coastguard Worker                expect(spiralEffect).toBeTruthy('spiral did not compile');
195*c8dee2aaSAndroid Build Coastguard Worker
196*c8dee2aaSAndroid Build Coastguard Worker                const brickShader = brickImg.makeShaderCubic(
197*c8dee2aaSAndroid Build Coastguard Worker                    CanvasKit.TileMode.Decal, CanvasKit.TileMode.Decal,
198*c8dee2aaSAndroid Build Coastguard Worker                    1/3 /*B*/, 1/3 /*C*/,
199*c8dee2aaSAndroid Build Coastguard Worker                    CanvasKit.Matrix.scaled(CANVAS_WIDTH/brickImg.width(),
200*c8dee2aaSAndroid Build Coastguard Worker                                            CANVAS_HEIGHT/brickImg.height()));
201*c8dee2aaSAndroid Build Coastguard Worker                const mandrillShader = mandrillImg.makeShaderCubic(
202*c8dee2aaSAndroid Build Coastguard Worker                    CanvasKit.TileMode.Decal, CanvasKit.TileMode.Decal,
203*c8dee2aaSAndroid Build Coastguard Worker                    1/3 /*B*/, 1/3 /*C*/,
204*c8dee2aaSAndroid Build Coastguard Worker                    CanvasKit.Matrix.scaled(CANVAS_WIDTH/mandrillImg.width(),
205*c8dee2aaSAndroid Build Coastguard Worker                                            CANVAS_HEIGHT/mandrillImg.height()));
206*c8dee2aaSAndroid Build Coastguard Worker                const spiralShader = spiralEffect.makeShader([
207*c8dee2aaSAndroid Build Coastguard Worker                    0.8,
208*c8dee2aaSAndroid Build Coastguard Worker                    CANVAS_WIDTH/2, CANVAS_HEIGHT/2,
209*c8dee2aaSAndroid Build Coastguard Worker                    1, 1, 1, 1,
210*c8dee2aaSAndroid Build Coastguard Worker                    0, 0, 0, 1]);
211*c8dee2aaSAndroid Build Coastguard Worker
212*c8dee2aaSAndroid Build Coastguard Worker                const blendShader = thresholdEffect.makeShaderWithChildren(
213*c8dee2aaSAndroid Build Coastguard Worker                    [0.5, 5],
214*c8dee2aaSAndroid Build Coastguard Worker                    [brickShader, mandrillShader, spiralShader], localMatrix);
215*c8dee2aaSAndroid Build Coastguard Worker
216*c8dee2aaSAndroid Build Coastguard Worker                const surface = CanvasKit.MakeCanvasSurface('test');
217*c8dee2aaSAndroid Build Coastguard Worker                expect(surface).toBeTruthy('Could not make surface');
218*c8dee2aaSAndroid Build Coastguard Worker                const canvas = surface.getCanvas();
219*c8dee2aaSAndroid Build Coastguard Worker                const paint = new CanvasKit.Paint();
220*c8dee2aaSAndroid Build Coastguard Worker
221*c8dee2aaSAndroid Build Coastguard Worker                paint.setShader(blendShader);
222*c8dee2aaSAndroid Build Coastguard Worker                canvas.drawRect(CanvasKit.LTRBRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), paint);
223*c8dee2aaSAndroid Build Coastguard Worker
224*c8dee2aaSAndroid Build Coastguard Worker                brickImg.delete();
225*c8dee2aaSAndroid Build Coastguard Worker                mandrillImg.delete();
226*c8dee2aaSAndroid Build Coastguard Worker                thresholdEffect.delete();
227*c8dee2aaSAndroid Build Coastguard Worker                spiralEffect.delete();
228*c8dee2aaSAndroid Build Coastguard Worker                brickShader.delete();
229*c8dee2aaSAndroid Build Coastguard Worker                mandrillShader.delete();
230*c8dee2aaSAndroid Build Coastguard Worker                spiralShader.delete();
231*c8dee2aaSAndroid Build Coastguard Worker                blendShader.delete();
232*c8dee2aaSAndroid Build Coastguard Worker                paint.delete();
233*c8dee2aaSAndroid Build Coastguard Worker
234*c8dee2aaSAndroid Build Coastguard Worker                reportSurface(surface, name, done);
235*c8dee2aaSAndroid Build Coastguard Worker            })();
236*c8dee2aaSAndroid Build Coastguard Worker        });
237*c8dee2aaSAndroid Build Coastguard Worker    }
238*c8dee2aaSAndroid Build Coastguard Worker
239*c8dee2aaSAndroid Build Coastguard Worker    it('take other shaders as fragment processors', (done) => {
240*c8dee2aaSAndroid Build Coastguard Worker        testChildrenShader('rtshader_children', done);
241*c8dee2aaSAndroid Build Coastguard Worker    });
242*c8dee2aaSAndroid Build Coastguard Worker
243*c8dee2aaSAndroid Build Coastguard Worker    it('apply a local matrix to the children-based shader', (done) => {
244*c8dee2aaSAndroid Build Coastguard Worker        testChildrenShader('rtshader_children_rotated', done, CanvasKit.Matrix.rotated(Math.PI/12));
245*c8dee2aaSAndroid Build Coastguard Worker    });
246*c8dee2aaSAndroid Build Coastguard Worker
247*c8dee2aaSAndroid Build Coastguard Worker    it('can generate runtime blender', (done) => {
248*c8dee2aaSAndroid Build Coastguard Worker        const loadBrick = fetch(
249*c8dee2aaSAndroid Build Coastguard Worker            '/assets/brickwork-texture.jpg')
250*c8dee2aaSAndroid Build Coastguard Worker            .then((response) => response.arrayBuffer());
251*c8dee2aaSAndroid Build Coastguard Worker        const loadMandrill = fetch(
252*c8dee2aaSAndroid Build Coastguard Worker            '/assets/mandrill_512.png')
253*c8dee2aaSAndroid Build Coastguard Worker            .then((response) => response.arrayBuffer());
254*c8dee2aaSAndroid Build Coastguard Worker        Promise.all([loadBrick, loadMandrill]).then((values) => {
255*c8dee2aaSAndroid Build Coastguard Worker            catchException(done, () => {
256*c8dee2aaSAndroid Build Coastguard Worker                const screenSkSL = `
257*c8dee2aaSAndroid Build Coastguard Worker                    vec4 main(vec4 src, vec4 dst) {
258*c8dee2aaSAndroid Build Coastguard Worker                        return src + dst - src * dst;
259*c8dee2aaSAndroid Build Coastguard Worker                    }
260*c8dee2aaSAndroid Build Coastguard Worker                `;
261*c8dee2aaSAndroid Build Coastguard Worker
262*c8dee2aaSAndroid Build Coastguard Worker                const [brickData, mandrillData] = values;
263*c8dee2aaSAndroid Build Coastguard Worker                const brickImg = CanvasKit.MakeImageFromEncoded(brickData);
264*c8dee2aaSAndroid Build Coastguard Worker                expect(brickImg)
265*c8dee2aaSAndroid Build Coastguard Worker                    .withContext('brick image could not be loaded')
266*c8dee2aaSAndroid Build Coastguard Worker                    .toBeTruthy();
267*c8dee2aaSAndroid Build Coastguard Worker                const mandrillImg = CanvasKit.MakeImageFromEncoded(mandrillData);
268*c8dee2aaSAndroid Build Coastguard Worker                expect(mandrillImg)
269*c8dee2aaSAndroid Build Coastguard Worker                    .withContext('mandrill image could not be loaded')
270*c8dee2aaSAndroid Build Coastguard Worker                    .toBeTruthy();
271*c8dee2aaSAndroid Build Coastguard Worker
272*c8dee2aaSAndroid Build Coastguard Worker                const brickShader = brickImg.makeShaderCubic(
273*c8dee2aaSAndroid Build Coastguard Worker                    CanvasKit.TileMode.Decal, CanvasKit.TileMode.Decal,
274*c8dee2aaSAndroid Build Coastguard Worker                    1/3 /*B*/, 1/3 /*C*/,
275*c8dee2aaSAndroid Build Coastguard Worker                    CanvasKit.Matrix.scaled(CANVAS_WIDTH/brickImg.width(),
276*c8dee2aaSAndroid Build Coastguard Worker                                            CANVAS_HEIGHT/brickImg.height()));
277*c8dee2aaSAndroid Build Coastguard Worker                const mandrillShader = mandrillImg.makeShaderCubic(
278*c8dee2aaSAndroid Build Coastguard Worker                    CanvasKit.TileMode.Decal, CanvasKit.TileMode.Decal,
279*c8dee2aaSAndroid Build Coastguard Worker                    1/3 /*B*/, 1/3 /*C*/,
280*c8dee2aaSAndroid Build Coastguard Worker                    CanvasKit.Matrix.scaled(CANVAS_WIDTH/mandrillImg.width(),
281*c8dee2aaSAndroid Build Coastguard Worker                                            CANVAS_HEIGHT/mandrillImg.height()));
282*c8dee2aaSAndroid Build Coastguard Worker
283*c8dee2aaSAndroid Build Coastguard Worker                const surface = CanvasKit.MakeCanvasSurface('test');
284*c8dee2aaSAndroid Build Coastguard Worker                expect(surface)
285*c8dee2aaSAndroid Build Coastguard Worker                    .withContext('Could not make surface')
286*c8dee2aaSAndroid Build Coastguard Worker                    .toBeTruthy();
287*c8dee2aaSAndroid Build Coastguard Worker                const canvas = surface.getCanvas();
288*c8dee2aaSAndroid Build Coastguard Worker                const paint = new CanvasKit.Paint();
289*c8dee2aaSAndroid Build Coastguard Worker
290*c8dee2aaSAndroid Build Coastguard Worker                const screenEffect = CanvasKit.RuntimeEffect.MakeForBlender(screenSkSL);
291*c8dee2aaSAndroid Build Coastguard Worker                expect(screenEffect)
292*c8dee2aaSAndroid Build Coastguard Worker                    .withContext('could not compile program')
293*c8dee2aaSAndroid Build Coastguard Worker                    .toBeTruthy();
294*c8dee2aaSAndroid Build Coastguard Worker                expect(screenEffect.getUniformCount()     ).toEqual(0);
295*c8dee2aaSAndroid Build Coastguard Worker                expect(screenEffect.getUniformFloatCount()).toEqual(0);
296*c8dee2aaSAndroid Build Coastguard Worker                const screenBlender = screenEffect.makeBlender([]);
297*c8dee2aaSAndroid Build Coastguard Worker
298*c8dee2aaSAndroid Build Coastguard Worker                paint.setShader(brickShader);
299*c8dee2aaSAndroid Build Coastguard Worker                canvas.drawRect(CanvasKit.LTRBRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), paint);
300*c8dee2aaSAndroid Build Coastguard Worker                paint.setShader(mandrillShader);
301*c8dee2aaSAndroid Build Coastguard Worker                paint.setBlender(screenBlender);
302*c8dee2aaSAndroid Build Coastguard Worker                canvas.drawRect(CanvasKit.LTRBRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), paint);
303*c8dee2aaSAndroid Build Coastguard Worker
304*c8dee2aaSAndroid Build Coastguard Worker                brickImg.delete();
305*c8dee2aaSAndroid Build Coastguard Worker                mandrillImg.delete();
306*c8dee2aaSAndroid Build Coastguard Worker                brickShader.delete();
307*c8dee2aaSAndroid Build Coastguard Worker                mandrillShader.delete();
308*c8dee2aaSAndroid Build Coastguard Worker                paint.delete();
309*c8dee2aaSAndroid Build Coastguard Worker                screenBlender.delete();
310*c8dee2aaSAndroid Build Coastguard Worker                screenEffect.delete();
311*c8dee2aaSAndroid Build Coastguard Worker
312*c8dee2aaSAndroid Build Coastguard Worker                reportSurface(surface, 'rtblender', done);
313*c8dee2aaSAndroid Build Coastguard Worker            })();
314*c8dee2aaSAndroid Build Coastguard Worker        });
315*c8dee2aaSAndroid Build Coastguard Worker    });
316*c8dee2aaSAndroid Build Coastguard Worker});
317