xref: /aosp_15_r20/external/skia/tests/RasterPipelineBuilderTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2022 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "include/core/SkStream.h"
9 #include "src/base/SkArenaAlloc.h"
10 #include "src/base/SkStringView.h"
11 #include "src/core/SkRasterPipeline.h"
12 #include "src/sksl/codegen/SkSLRasterPipelineBuilder.h"
13 #include "src/sksl/tracing/SkSLDebugTracePriv.h"
14 #include "tests/Test.h"
15 
get_program_dump(SkSL::RP::Program & program)16 static sk_sp<SkData> get_program_dump(SkSL::RP::Program& program) {
17     SkDynamicMemoryWStream stream;
18     program.dump(&stream);
19     return stream.detachAsData();
20 }
21 
as_string_view(const sk_sp<SkData> & dump)22 static std::string_view as_string_view(const sk_sp<SkData>& dump) {
23     return std::string_view(static_cast<const char*>(dump->data()), dump->size());
24 }
25 
check(skiatest::Reporter * r,SkSL::RP::Program & program,std::string_view expected)26 static void check(skiatest::Reporter* r, SkSL::RP::Program& program, std::string_view expected) {
27     // Verify that the program matches expectations.
28     sk_sp<SkData> dump = get_program_dump(program);
29     REPORTER_ASSERT(r, as_string_view(dump) == expected,
30                     "Output did not match expectation:\n%.*s",
31                     (int)dump->size(), static_cast<const char*>(dump->data()));
32 }
33 
one_slot_at(SkSL::RP::Slot index)34 static SkSL::RP::SlotRange one_slot_at(SkSL::RP::Slot index) {
35     return SkSL::RP::SlotRange{index, 1};
36 }
37 
two_slots_at(SkSL::RP::Slot index)38 static SkSL::RP::SlotRange two_slots_at(SkSL::RP::Slot index) {
39     return SkSL::RP::SlotRange{index, 2};
40 }
41 
three_slots_at(SkSL::RP::Slot index)42 static SkSL::RP::SlotRange three_slots_at(SkSL::RP::Slot index) {
43     return SkSL::RP::SlotRange{index, 3};
44 }
45 
four_slots_at(SkSL::RP::Slot index)46 static SkSL::RP::SlotRange four_slots_at(SkSL::RP::Slot index) {
47     return SkSL::RP::SlotRange{index, 4};
48 }
49 
five_slots_at(SkSL::RP::Slot index)50 static SkSL::RP::SlotRange five_slots_at(SkSL::RP::Slot index) {
51     return SkSL::RP::SlotRange{index, 5};
52 }
53 
ten_slots_at(SkSL::RP::Slot index)54 static SkSL::RP::SlotRange ten_slots_at(SkSL::RP::Slot index) {
55     return SkSL::RP::SlotRange{index, 10};
56 }
57 
DEF_TEST(RasterPipelineBuilder,r)58 DEF_TEST(RasterPipelineBuilder, r) {
59     // Create a very simple nonsense program.
60     SkSL::RP::Builder builder;
61     builder.store_src_rg(two_slots_at(0));
62     builder.store_src(four_slots_at(2));
63     builder.store_dst(four_slots_at(4));
64     builder.store_device_xy01(four_slots_at(6));
65     builder.init_lane_masks();
66     builder.enableExecutionMaskWrites();
67     builder.mask_off_return_mask();
68     builder.mask_off_loop_mask();
69     builder.reenable_loop_mask(one_slot_at(4));
70     builder.disableExecutionMaskWrites();
71     builder.load_src(four_slots_at(1));
72     builder.load_dst(four_slots_at(3));
73     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/10,
74                                                                 /*numUniformSlots=*/0,
75                                                                 /*numImmutableSlots=*/0);
76     check(r, *program,
77 R"(store_src_rg                   v0..1 = src.rg
78 store_src                      v2..5 = src.rgba
79 store_dst                      v4..7 = dst.rgba
80 store_device_xy01              v6..9 = DeviceCoords.xy01
81 init_lane_masks                CondMask = LoopMask = RetMask = true
82 mask_off_return_mask           RetMask &= ~(CondMask & LoopMask & RetMask)
83 mask_off_loop_mask             LoopMask &= ~(CondMask & LoopMask & RetMask)
84 reenable_loop_mask             LoopMask |= v4
85 load_src                       src.rgba = v1..4
86 load_dst                       dst.rgba = v3..6
87 )");
88 }
89 
DEF_TEST(RasterPipelineBuilderPushPopMaskRegisters,r)90 DEF_TEST(RasterPipelineBuilderPushPopMaskRegisters, r) {
91     // Create a very simple nonsense program.
92     SkSL::RP::Builder builder;
93 
94     REPORTER_ASSERT(r, !builder.executionMaskWritesAreEnabled());
95     builder.enableExecutionMaskWrites();
96     REPORTER_ASSERT(r, builder.executionMaskWritesAreEnabled());
97 
98     builder.push_condition_mask();         // push into 0
99     builder.push_loop_mask();              // push into 1
100     builder.push_return_mask();            // push into 2
101     builder.merge_condition_mask();        // set the condition-mask to 1 & 2
102     builder.merge_inv_condition_mask();    // set the condition-mask to 1 & ~2
103     builder.pop_condition_mask();          // pop from 2
104     builder.merge_loop_mask();             // mask off the loop-mask against 1
105     builder.push_condition_mask();         // push into 2
106     builder.pop_condition_mask();          // pop from 2
107     builder.pop_loop_mask();               // pop from 1
108     builder.pop_return_mask();             // pop from 0
109     builder.push_condition_mask();         // push into 0
110     builder.pop_and_reenable_loop_mask();  // pop from 0
111 
112     REPORTER_ASSERT(r, builder.executionMaskWritesAreEnabled());
113     builder.disableExecutionMaskWrites();
114     REPORTER_ASSERT(r, !builder.executionMaskWritesAreEnabled());
115 
116     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/0,
117                                                                 /*numUniformSlots=*/0,
118                                                                 /*numImmutableSlots=*/0);
119     check(r, *program,
120 R"(store_condition_mask           $0 = CondMask
121 store_loop_mask                $1 = LoopMask
122 store_return_mask              $2 = RetMask
123 merge_condition_mask           CondMask = $1 & $2
124 merge_inv_condition_mask       CondMask = $1 & ~$2
125 load_condition_mask            CondMask = $2
126 merge_loop_mask                LoopMask &= $1
127 store_condition_mask           $2 = CondMask
128 load_condition_mask            CondMask = $2
129 load_loop_mask                 LoopMask = $1
130 load_return_mask               RetMask = $0
131 store_condition_mask           $0 = CondMask
132 reenable_loop_mask             LoopMask |= $0
133 )");
134 }
135 
136 
DEF_TEST(RasterPipelineBuilderCaseOp,r)137 DEF_TEST(RasterPipelineBuilderCaseOp, r) {
138     // Create a very simple nonsense program.
139     SkSL::RP::Builder builder;
140 
141     builder.push_constant_i(123);  // push a test value
142     builder.push_constant_i(~0);   // push an all-on default mask
143     builder.case_op(123);          // do `case 123:`
144     builder.case_op(124);          // do `case 124:`
145     builder.discard_stack(2);
146 
147     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/0,
148                                                                 /*numUniformSlots=*/0,
149                                                                 /*numImmutableSlots=*/0);
150     check(r, *program,
151 R"(copy_constant                  $0 = 0x0000007B (1.723597e-43)
152 copy_constant                  $1 = 0xFFFFFFFF
153 case_op                        if ($0 == 0x0000007B) { LoopMask = true; $1 = false; }
154 case_op                        if ($0 == 0x0000007C) { LoopMask = true; $1 = false; }
155 )");
156 }
157 
DEF_TEST(RasterPipelineBuilderPushPopSrcDst,r)158 DEF_TEST(RasterPipelineBuilderPushPopSrcDst, r) {
159     // Create a very simple nonsense program.
160     SkSL::RP::Builder builder;
161 
162     builder.push_src_rgba();
163     builder.push_dst_rgba();
164     builder.pop_src_rgba();
165     builder.exchange_src();
166     builder.exchange_src();
167     builder.exchange_src();
168     builder.pop_dst_rgba();
169 
170     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/0,
171                                                                 /*numUniformSlots=*/0,
172                                                                 /*numImmutableSlots=*/0);
173     check(r, *program,
174 R"(store_src                      $0..3 = src.rgba
175 store_dst                      $4..7 = dst.rgba
176 load_src                       src.rgba = $4..7
177 exchange_src                   swap(src.rgba, $0..3)
178 load_dst                       dst.rgba = $0..3
179 )");
180 }
181 
DEF_TEST(RasterPipelineBuilderInvokeChild,r)182 DEF_TEST(RasterPipelineBuilderInvokeChild, r) {
183     // Create a very simple nonsense program.
184     SkSL::RP::Builder builder;
185 
186     builder.invoke_shader(1);
187     builder.invoke_color_filter(2);
188     builder.invoke_blender(3);
189 
190     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/0,
191                                                                 /*numUniformSlots=*/0,
192                                                                 /*numImmutableSlots=*/0);
193 check(r, *program,
194 R"(invoke_shader                  invoke_shader 0x00000001
195 invoke_color_filter            invoke_color_filter 0x00000002
196 invoke_blender                 invoke_blender 0x00000003
197 )");
198 }
199 
DEF_TEST(RasterPipelineBuilderPushPopTempImmediates,r)200 DEF_TEST(RasterPipelineBuilderPushPopTempImmediates, r) {
201     // Create a very simple nonsense program.
202     SkSL::RP::Builder builder;
203     builder.set_current_stack(1);
204     builder.push_constant_i(999);                                         // push into 2
205     builder.set_current_stack(0);
206     builder.push_constant_f(13.5f);                                       // push into 0
207     builder.push_clone_from_stack(one_slot_at(0), /*otherStackID=*/1, /*offsetFromStackTop=*/1);
208                                                                           // push into 1 from 2
209     builder.discard_stack(1);                                             // discard 2
210     builder.push_constant_u(357);                                         // push into 2
211     builder.set_current_stack(1);
212     builder.push_clone_from_stack(one_slot_at(0), /*otherStackID=*/0, /*offsetFromStackTop=*/1);
213                                                                           // push into 3 from 0
214     builder.discard_stack(2);                                             // discard 2 and 3
215     builder.set_current_stack(0);
216     builder.push_constant_f(1.2f);                                        // push into 2
217     builder.pad_stack(3);                                                 // pad slots 3,4,5
218     builder.push_constant_f(3.4f);                                        // push into 6
219     builder.discard_stack(7);                                             // discard 0 through 6
220     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/1,
221                                                                 /*numUniformSlots=*/0,
222                                                                 /*numImmutableSlots=*/0);
223     check(r, *program,
224 R"(copy_constant                  $2 = 0x000003E7 (1.399897e-42)
225 copy_constant                  $0 = 0x41580000 (13.5)
226 copy_constant                  $1 = 0x00000165 (5.002636e-43)
227 )");
228 }
229 
DEF_TEST(RasterPipelineBuilderPushPopIndirect,r)230 DEF_TEST(RasterPipelineBuilderPushPopIndirect, r) {
231     // Create a very simple nonsense program.
232     SkSL::RP::Builder builder;
233     builder.set_current_stack(1);
234     builder.push_constant_i(3);
235     builder.set_current_stack(0);
236     builder.push_slots_indirect(two_slots_at(0), /*dynamicStack=*/1, ten_slots_at(0));
237     builder.push_slots_indirect(four_slots_at(10), /*dynamicStack=*/1, ten_slots_at(10));
238     builder.push_uniform_indirect(one_slot_at(0), /*dynamicStack=*/1, five_slots_at(0));
239     builder.push_uniform_indirect(three_slots_at(5), /*dynamicStack=*/1, five_slots_at(5));
240     builder.swizzle_copy_stack_to_slots_indirect(three_slots_at(6), /*dynamicStackID=*/1,
241                                                  ten_slots_at(0), {2, 1, 0},
242                                                  /*offsetFromStackTop=*/3);
243     builder.copy_stack_to_slots_indirect(three_slots_at(4), /*dynamicStackID=*/1, ten_slots_at(0));
244     builder.pop_slots_indirect(five_slots_at(0), /*dynamicStackID=*/1, ten_slots_at(0));
245     builder.pop_slots_indirect(five_slots_at(10), /*dynamicStackID=*/1, ten_slots_at(10));
246     builder.set_current_stack(1);
247     builder.discard_stack(1);
248     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/20,
249                                                                 /*numUniformSlots=*/10,
250                                                                 /*numImmutableSlots=*/0);
251     check(r, *program,
252 R"(copy_constant                  $10 = 0x00000003 (4.203895e-45)
253 copy_from_indirect_unmasked    $0..1 = Indirect(v0..1 + $10)
254 copy_from_indirect_unmasked    $2..5 = Indirect(v10..13 + $10)
255 copy_from_indirect_uniform_unm $6 = Indirect(u0 + $10)
256 copy_from_indirect_uniform_unm $7..9 = Indirect(u5..7 + $10)
257 swizzle_copy_to_indirect_maske Indirect(v6..8 + $10).zyx = Mask($7..9)
258 copy_to_indirect_masked        Indirect(v4..6 + $10) = Mask($7..9)
259 copy_to_indirect_masked        Indirect(v0..4 + $10) = Mask($5..9)
260 copy_to_indirect_masked        Indirect(v10..14 + $10) = Mask($0..4)
261 )");
262 }
263 
DEF_TEST(RasterPipelineBuilderCopySlotsMasked,r)264 DEF_TEST(RasterPipelineBuilderCopySlotsMasked, r) {
265     // Create a very simple nonsense program.
266     SkSL::RP::Builder builder;
267     builder.copy_slots_masked(two_slots_at(0),  two_slots_at(2));
268     builder.copy_slots_masked(four_slots_at(1), four_slots_at(5));
269     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/9,
270                                                                 /*numUniformSlots=*/0,
271                                                                 /*numImmutableSlots=*/0);
272     check(r, *program,
273 R"(copy_2_slots_masked            v0..1 = Mask(v2..3)
274 copy_4_slots_masked            v1..4 = Mask(v5..8)
275 )");
276 }
277 
DEF_TEST(RasterPipelineBuilderCopySlotsUnmasked,r)278 DEF_TEST(RasterPipelineBuilderCopySlotsUnmasked, r) {
279     // Create a very simple nonsense program.
280     SkSL::RP::Builder builder;
281     builder.copy_slots_unmasked(three_slots_at(0), three_slots_at(2));
282     builder.copy_slots_unmasked(five_slots_at(1),  five_slots_at(5));
283     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/10,
284                                                                 /*numUniformSlots=*/0,
285                                                                 /*numImmutableSlots=*/0);
286     check(r, *program,
287 R"(copy_3_slots_unmasked          v0..2 = v2..4
288 copy_4_slots_unmasked          v1..4 = v5..8
289 copy_slot_unmasked             v5 = v9
290 )");
291 }
292 
DEF_TEST(RasterPipelineBuilderPushPopSlots,r)293 DEF_TEST(RasterPipelineBuilderPushPopSlots, r) {
294     // Create a very simple nonsense program.
295     SkSL::RP::Builder builder;
296     builder.push_slots(four_slots_at(10));           // push from 10~13 into $0~$3
297     builder.copy_stack_to_slots(one_slot_at(5), 3);  // copy from $1 into 5
298     builder.pop_slots_unmasked(two_slots_at(20));    // pop from $2~$3 into 20~21 (unmasked)
299     builder.enableExecutionMaskWrites();
300     builder.copy_stack_to_slots_unmasked(one_slot_at(4), 2);  // copy from $0 into 4
301     builder.push_slots(three_slots_at(30));          // push from 30~32 into $2~$4
302     builder.pop_slots(five_slots_at(0));             // pop from $0~$4 into 0~4 (masked)
303     builder.disableExecutionMaskWrites();
304 
305     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/50,
306                                                                 /*numUniformSlots=*/0,
307                                                                 /*numImmutableSlots=*/0);
308     check(r, *program,
309 R"(copy_4_slots_unmasked          $0..3 = v10..13
310 copy_slot_unmasked             v5 = $1
311 copy_2_slots_unmasked          v20..21 = $2..3
312 copy_slot_unmasked             v4 = $0
313 copy_3_slots_unmasked          $2..4 = v30..32
314 copy_4_slots_masked            v0..3 = Mask($0..3)
315 copy_slot_masked               v4 = Mask($4)
316 )");
317 }
318 
DEF_TEST(RasterPipelineBuilderDuplicateSelectAndSwizzleSlots,r)319 DEF_TEST(RasterPipelineBuilderDuplicateSelectAndSwizzleSlots, r) {
320     // Create a very simple nonsense program.
321     SkSL::RP::Builder builder;
322     builder.push_constant_f(1.0f);          // push into 0
323     builder.push_duplicates(1);             // duplicate into 1
324     builder.push_duplicates(2);             // duplicate into 2~3
325     builder.push_duplicates(3);             // duplicate into 4~6
326     builder.push_duplicates(5);             // duplicate into 7~11
327     builder.select(4);                      // select from 4~7 and 8~11 into 4~7
328     builder.select(3);                      // select from 2~4 and 5~7 into 2~4
329     builder.select(1);                      // select from 3 and 4 into 3
330     builder.swizzle_copy_stack_to_slots(four_slots_at(1), {3, 2, 1, 0}, 4);
331     builder.swizzle_copy_stack_to_slots(four_slots_at(0), {0, 1, 3}, 3);
332     builder.swizzle(4, {3, 2, 1, 0});       // reverse the order of 0~3 (value.wzyx)
333     builder.swizzle(4, {1, 2});             // eliminate elements 0 and 3 (value.yz)
334     builder.swizzle(2, {0});                // eliminate element 1 (value.x)
335     builder.discard_stack(1);               // balance stack
336     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/6,
337                                                                 /*numUniformSlots=*/0,
338                                                                 /*numImmutableSlots=*/0);
339     check(r, *program,
340 R"(splat_4_constants              $0..3 = 0x3F800000 (1.0)
341 splat_4_constants              $4..7 = 0x3F800000 (1.0)
342 splat_4_constants              $8..11 = 0x3F800000 (1.0)
343 copy_4_slots_masked            $4..7 = Mask($8..11)
344 copy_3_slots_masked            $2..4 = Mask($5..7)
345 copy_slot_masked               $3 = Mask($4)
346 swizzle_copy_4_slots_masked    (v1..4).wzyx = Mask($0..3)
347 swizzle_copy_3_slots_masked    (v0..3).xyw = Mask($1..3)
348 swizzle_4                      $0..3 = ($0..3).wzyx
349 swizzle_2                      $0..1 = ($0..2).yz
350 )");
351 }
352 
DEF_TEST(RasterPipelineBuilderTransposeMatrix,r)353 DEF_TEST(RasterPipelineBuilderTransposeMatrix, r) {
354     // Create a very simple nonsense program.
355     SkSL::RP::Builder builder;
356     builder.push_constant_f(1.0f);          // push into 0
357     builder.push_duplicates(15);            // duplicate into 1~15
358     builder.transpose(2, 2);                // transpose a 2x2 matrix
359     builder.transpose(3, 3);                // transpose a 3x3 matrix
360     builder.transpose(4, 4);                // transpose a 4x4 matrix
361     builder.transpose(2, 4);                // transpose a 2x4 matrix
362     builder.transpose(4, 3);                // transpose a 4x3 matrix
363     builder.discard_stack(16);              // balance stack
364     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/0,
365                                                                 /*numUniformSlots=*/0,
366                                                                 /*numImmutableSlots=*/0);
367     check(r, *program,
368 R"(splat_4_constants              $0..3 = 0x3F800000 (1.0)
369 splat_4_constants              $4..7 = 0x3F800000 (1.0)
370 splat_4_constants              $8..11 = 0x3F800000 (1.0)
371 splat_4_constants              $12..15 = 0x3F800000 (1.0)
372 swizzle_3                      $13..15 = ($13..15).yxz
373 shuffle                        $8..15 = ($8..15)[2 5 0 3 6 1 4 7]
374 shuffle                        $1..15 = ($1..15)[3 7 11 0 4 8 12 1 5 9 13 2 6 10 14]
375 shuffle                        $9..15 = ($9..15)[3 0 4 1 5 2 6]
376 shuffle                        $5..15 = ($5..15)[2 5 8 0 3 6 9 1 4 7 10]
377 )");
378 }
379 
DEF_TEST(RasterPipelineBuilderDiagonalMatrix,r)380 DEF_TEST(RasterPipelineBuilderDiagonalMatrix, r) {
381     // Create a very simple nonsense program.
382     SkSL::RP::Builder builder;
383     builder.push_constant_f(0.0f);          // push into 0
384     builder.push_constant_f(1.0f);          // push into 1
385     builder.diagonal_matrix(2, 2);          // generate a 2x2 diagonal matrix
386     builder.discard_stack(4);               // balance stack
387     builder.push_constant_f(0.0f);          // push into 0
388     builder.push_constant_f(2.0f);          // push into 1
389     builder.diagonal_matrix(4, 4);          // generate a 4x4 diagonal matrix
390     builder.discard_stack(16);              // balance stack
391     builder.push_constant_f(0.0f);          // push into 0
392     builder.push_constant_f(3.0f);          // push into 1
393     builder.diagonal_matrix(2, 3);          // generate a 2x3 diagonal matrix
394     builder.discard_stack(6);               // balance stack
395     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/0,
396                                                                 /*numUniformSlots=*/0,
397                                                                 /*numImmutableSlots=*/0);
398     check(r, *program,
399 R"(copy_constant                  $0 = 0
400 copy_constant                  $1 = 0x3F800000 (1.0)
401 swizzle_4                      $0..3 = ($0..3).yxxy
402 copy_constant                  $0 = 0
403 copy_constant                  $1 = 0x40000000 (2.0)
404 shuffle                        $0..15 = ($0..15)[1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1]
405 copy_constant                  $0 = 0
406 copy_constant                  $1 = 0x40400000 (3.0)
407 shuffle                        $0..5 = ($0..5)[1 0 0 0 1 0]
408 )");
409 }
410 
DEF_TEST(RasterPipelineBuilderMatrixResize,r)411 DEF_TEST(RasterPipelineBuilderMatrixResize, r) {
412     // Create a very simple nonsense program.
413     SkSL::RP::Builder builder;
414     builder.push_constant_f(1.0f);          // synthesize a 2x2 matrix
415     builder.push_constant_f(2.0f);
416     builder.push_constant_f(3.0f);
417     builder.push_constant_f(4.0f);
418     builder.matrix_resize(2, 2, 4, 4);      // resize 2x2 matrix into 4x4
419     builder.matrix_resize(4, 4, 2, 2);      // resize 4x4 matrix back into 2x2
420     builder.matrix_resize(2, 2, 2, 4);      // resize 2x2 matrix into 2x4
421     builder.matrix_resize(2, 4, 4, 2);      // resize 2x4 matrix into 4x2
422     builder.matrix_resize(4, 2, 3, 3);      // resize 4x2 matrix into 3x3
423     builder.discard_stack(9);               // balance stack
424     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/0,
425                                                                 /*numUniformSlots=*/0,
426                                                                 /*numImmutableSlots=*/0);
427     check(r, *program,
428 R"(copy_constant                  $0 = 0x3F800000 (1.0)
429 copy_constant                  $1 = 0x40000000 (2.0)
430 copy_constant                  $2 = 0x40400000 (3.0)
431 copy_constant                  $3 = 0x40800000 (4.0)
432 copy_constant                  $4 = 0
433 copy_constant                  $5 = 0x3F800000 (1.0)
434 shuffle                        $2..15 = ($2..15)[2 2 0 1 2 2 2 2 3 2 2 2 2 3]
435 shuffle                        $2..3 = ($2..3)[2 3]
436 copy_constant                  $4 = 0
437 shuffle                        $2..7 = ($2..7)[2 2 0 1 2 2]
438 copy_constant                  $8 = 0
439 shuffle                        $2..7 = ($2..7)[2 3 6 6 6 6]
440 copy_constant                  $8 = 0
441 copy_constant                  $9 = 0x3F800000 (1.0)
442 shuffle                        $2..8 = ($2..8)[6 0 1 6 2 3 7]
443 )");
444 }
445 
DEF_TEST(RasterPipelineBuilderBranches,r)446 DEF_TEST(RasterPipelineBuilderBranches, r) {
447 #if SK_HAS_MUSTTAIL
448     // We have guaranteed tail-calling, and don't need to rewind the stack.
449     static constexpr char kExpectationWithKnownExecutionMask[] =
450 R"(jump                           jump +9 (label 3 at #10)
451 label                          label 0
452 copy_constant                  v0 = 0
453 label                          label 0x00000001
454 copy_constant                  v1 = 0
455 jump                           jump -4 (label 0 at #2)
456 label                          label 0x00000002
457 copy_constant                  v2 = 0
458 jump                           jump -7 (label 0 at #2)
459 label                          label 0x00000003
460 branch_if_no_active_lanes_eq   branch -4 (label 2 at #7) if no lanes of v2 == 0
461 branch_if_no_active_lanes_eq   branch -10 (label 0 at #2) if no lanes of v2 == 0x00000001 (1.401298e-45)
462 )";
463     static constexpr char kExpectationWithExecutionMaskWrites[] =
464 R"(jump                           jump +10 (label 3 at #11)
465 label                          label 0
466 copy_constant                  v0 = 0
467 label                          label 0x00000001
468 copy_constant                  v1 = 0
469 branch_if_no_lanes_active      branch_if_no_lanes_active -2 (label 1 at #4)
470 branch_if_all_lanes_active     branch_if_all_lanes_active -5 (label 0 at #2)
471 label                          label 0x00000002
472 copy_constant                  v2 = 0
473 branch_if_any_lanes_active     branch_if_any_lanes_active -8 (label 0 at #2)
474 label                          label 0x00000003
475 branch_if_no_active_lanes_eq   branch -4 (label 2 at #8) if no lanes of v2 == 0
476 branch_if_no_active_lanes_eq   branch -11 (label 0 at #2) if no lanes of v2 == 0x00000001 (1.401298e-45)
477 )";
478 #else
479     // We don't have guaranteed tail-calling, so we rewind the stack immediately before any backward
480     // branches.
481     static constexpr char kExpectationWithKnownExecutionMask[] =
482 R"(jump                           jump +11 (label 3 at #12)
483 label                          label 0
484 copy_constant                  v0 = 0
485 label                          label 0x00000001
486 copy_constant                  v1 = 0
487 stack_rewind
488 jump                           jump -5 (label 0 at #2)
489 label                          label 0x00000002
490 copy_constant                  v2 = 0
491 stack_rewind
492 jump                           jump -9 (label 0 at #2)
493 label                          label 0x00000003
494 stack_rewind
495 branch_if_no_active_lanes_eq   branch -6 (label 2 at #8) if no lanes of v2 == 0
496 stack_rewind
497 branch_if_no_active_lanes_eq   branch -14 (label 0 at #2) if no lanes of v2 == 0x00000001 (1.401298e-45)
498 )";
499     static constexpr char kExpectationWithExecutionMaskWrites[] =
500 R"(jump                           jump +13 (label 3 at #14)
501 label                          label 0
502 copy_constant                  v0 = 0
503 label                          label 0x00000001
504 copy_constant                  v1 = 0
505 stack_rewind
506 branch_if_no_lanes_active      branch_if_no_lanes_active -3 (label 1 at #4)
507 stack_rewind
508 branch_if_all_lanes_active     branch_if_all_lanes_active -7 (label 0 at #2)
509 label                          label 0x00000002
510 copy_constant                  v2 = 0
511 stack_rewind
512 branch_if_any_lanes_active     branch_if_any_lanes_active -11 (label 0 at #2)
513 label                          label 0x00000003
514 stack_rewind
515 branch_if_no_active_lanes_eq   branch -6 (label 2 at #10) if no lanes of v2 == 0
516 stack_rewind
517 branch_if_no_active_lanes_eq   branch -16 (label 0 at #2) if no lanes of v2 == 0x00000001 (1.401298e-45)
518 )";
519 #endif
520 
521     for (bool enableExecutionMaskWrites : {false, true}) {
522         // Create a very simple nonsense program.
523         SkSL::RP::Builder builder;
524         int label1 = builder.nextLabelID();
525         int label2 = builder.nextLabelID();
526         int label3 = builder.nextLabelID();
527         int label4 = builder.nextLabelID();
528 
529         if (enableExecutionMaskWrites) {
530             builder.enableExecutionMaskWrites();
531         }
532 
533         builder.jump(label4);
534         builder.label(label1);
535         builder.zero_slots_unmasked(one_slot_at(0));
536         builder.label(label2);
537         builder.zero_slots_unmasked(one_slot_at(1));
538         builder.branch_if_no_lanes_active(label2);
539         builder.branch_if_no_lanes_active(label3);
540         builder.branch_if_all_lanes_active(label1);
541         builder.label(label3);
542         builder.zero_slots_unmasked(one_slot_at(2));
543         builder.branch_if_any_lanes_active(label1);
544         builder.branch_if_any_lanes_active(label1);
545         builder.label(label4);
546         builder.branch_if_no_active_lanes_on_stack_top_equal(0, label3);
547         builder.branch_if_no_active_lanes_on_stack_top_equal(0, label2);
548         builder.branch_if_no_active_lanes_on_stack_top_equal(1, label1);
549         builder.branch_if_no_active_lanes_on_stack_top_equal(1, label4);
550 
551         if (enableExecutionMaskWrites) {
552             builder.disableExecutionMaskWrites();
553         }
554 
555         std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/3,
556                                                                     /*numUniformSlots=*/0,
557                                                                     /*numImmutableSlots=*/0);
558 
559         check(r, *program, enableExecutionMaskWrites ? kExpectationWithExecutionMaskWrites
560                                                      : kExpectationWithKnownExecutionMask);
561     }
562 }
563 
DEF_TEST(RasterPipelineBuilderBackwardsBranchOverInvocationShouldRewind,r)564 DEF_TEST(RasterPipelineBuilderBackwardsBranchOverInvocationShouldRewind, r) {
565     // Branching backward over a call to invoke_shader should always emit a stack_rewind op.
566     SkSL::RP::Builder builder;
567     int label1 = builder.nextLabelID();
568     builder.push_constant_f(10.0f);
569     builder.label(label1);
570     builder.push_constant_f(20.0f);
571     builder.invoke_shader(9);
572     builder.push_constant_f(30.0f);
573     builder.discard_stack(3);
574     builder.branch_if_any_lanes_active(label1);
575 
576     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/3,
577                                                                 /*numUniformSlots=*/0,
578                                                                 /*numImmutableSlots=*/0);
579     check(r, *program,
580 R"(copy_constant                  $0 = 0x41200000 (10.0)
581 label                          label 0
582 copy_constant                  $1 = 0x41A00000 (20.0)
583 invoke_shader                  invoke_shader 0x00000009
584 stack_rewind
585 jump                           jump -4 (label 0 at #2)
586 )");
587 }
588 
DEF_TEST(RasterPipelineBuilderBackwardsBranchWithoutInvocationMightNotRewind,r)589 DEF_TEST(RasterPipelineBuilderBackwardsBranchWithoutInvocationMightNotRewind, r) {
590     SkSL::RP::Builder builder;
591     int label1 = builder.nextLabelID();
592     builder.push_constant_f(10.0f);
593     builder.invoke_shader(9);
594     builder.push_constant_f(20.0f);
595     builder.label(label1);
596     builder.push_constant_f(30.0f);
597     builder.discard_stack(3);
598     builder.branch_if_any_lanes_active(label1);
599 
600     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/3,
601                                                                 /*numUniformSlots=*/0,
602                                                                 /*numImmutableSlots=*/0);
603 #if SK_HAS_MUSTTAIL
604     check(r, *program,
605 R"(copy_constant                  $0 = 0x41200000 (10.0)
606 invoke_shader                  invoke_shader 0x00000009
607 copy_constant                  $1 = 0x41A00000 (20.0)
608 label                          label 0
609 jump                           jump -1 (label 0 at #4)
610 )");
611 #else
612     check(r, *program,
613 R"(copy_constant                  $0 = 0x41200000 (10.0)
614 invoke_shader                  invoke_shader 0x00000009
615 copy_constant                  $1 = 0x41A00000 (20.0)
616 label                          label 0
617 stack_rewind
618 jump                           jump -2 (label 0 at #4)
619 )");
620 #endif
621 }
622 
DEF_TEST(RasterPipelineBuilderBinaryFloatOps,r)623 DEF_TEST(RasterPipelineBuilderBinaryFloatOps, r) {
624     using BuilderOp = SkSL::RP::BuilderOp;
625 
626     SkSL::RP::Builder builder;
627     builder.push_constant_f(10.0f);
628     builder.push_duplicates(30);
629     builder.binary_op(BuilderOp::add_n_floats, 1);
630     builder.binary_op(BuilderOp::sub_n_floats, 2);
631     builder.binary_op(BuilderOp::mul_n_floats, 3);
632     builder.binary_op(BuilderOp::div_n_floats, 4);
633     builder.binary_op(BuilderOp::max_n_floats, 3);
634     builder.binary_op(BuilderOp::min_n_floats, 2);
635     builder.binary_op(BuilderOp::cmplt_n_floats, 5);
636     builder.binary_op(BuilderOp::cmple_n_floats, 4);
637     builder.binary_op(BuilderOp::cmpeq_n_floats, 3);
638     builder.binary_op(BuilderOp::cmpne_n_floats, 2);
639     builder.discard_stack(2);
640     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/0,
641                                                                 /*numUniformSlots=*/0,
642                                                                 /*numImmutableSlots=*/0);
643     check(r, *program,
644 R"(splat_4_constants              $0..3 = 0x41200000 (10.0)
645 splat_4_constants              $4..7 = 0x41200000 (10.0)
646 splat_4_constants              $8..11 = 0x41200000 (10.0)
647 splat_4_constants              $12..15 = 0x41200000 (10.0)
648 splat_4_constants              $16..19 = 0x41200000 (10.0)
649 splat_4_constants              $20..23 = 0x41200000 (10.0)
650 splat_4_constants              $24..27 = 0x41200000 (10.0)
651 splat_2_constants              $28..29 = 0x41200000 (10.0)
652 add_imm_float                  $29 += 0x41200000 (10.0)
653 sub_2_floats                   $26..27 -= $28..29
654 mul_3_floats                   $22..24 *= $25..27
655 div_4_floats                   $17..20 /= $21..24
656 max_3_floats                   $15..17 = max($15..17, $18..20)
657 min_2_floats                   $14..15 = min($14..15, $16..17)
658 cmplt_n_floats                 $6..10 = lessThan($6..10, $11..15)
659 cmple_4_floats                 $3..6 = lessThanEqual($3..6, $7..10)
660 cmpeq_3_floats                 $1..3 = equal($1..3, $4..6)
661 cmpne_2_floats                 $0..1 = notEqual($0..1, $2..3)
662 )");
663 }
664 
DEF_TEST(RasterPipelineBuilderBinaryIntOps,r)665 DEF_TEST(RasterPipelineBuilderBinaryIntOps, r) {
666     using BuilderOp = SkSL::RP::BuilderOp;
667 
668     SkSL::RP::Builder builder;
669     builder.push_constant_i(123);
670     builder.push_duplicates(40);
671     builder.binary_op(BuilderOp::bitwise_and_n_ints, 1);
672     builder.binary_op(BuilderOp::bitwise_xor_n_ints, 2);
673     builder.binary_op(BuilderOp::bitwise_or_n_ints, 3);
674     builder.binary_op(BuilderOp::add_n_ints, 2);
675     builder.binary_op(BuilderOp::sub_n_ints, 3);
676     builder.binary_op(BuilderOp::mul_n_ints, 4);
677     builder.binary_op(BuilderOp::div_n_ints, 5);
678     builder.binary_op(BuilderOp::max_n_ints, 4);
679     builder.binary_op(BuilderOp::min_n_ints, 3);
680     builder.binary_op(BuilderOp::cmplt_n_ints, 1);
681     builder.binary_op(BuilderOp::cmple_n_ints, 2);
682     builder.binary_op(BuilderOp::cmpeq_n_ints, 3);
683     builder.binary_op(BuilderOp::cmpne_n_ints, 4);
684     builder.discard_stack(4);
685     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/0,
686                                                                 /*numUniformSlots=*/0,
687                                                                 /*numImmutableSlots=*/0);
688     check(r, *program,
689 R"(splat_4_constants              $0..3 = 0x0000007B (1.723597e-43)
690 splat_4_constants              $4..7 = 0x0000007B (1.723597e-43)
691 splat_4_constants              $8..11 = 0x0000007B (1.723597e-43)
692 splat_4_constants              $12..15 = 0x0000007B (1.723597e-43)
693 splat_4_constants              $16..19 = 0x0000007B (1.723597e-43)
694 splat_4_constants              $20..23 = 0x0000007B (1.723597e-43)
695 splat_4_constants              $24..27 = 0x0000007B (1.723597e-43)
696 splat_4_constants              $28..31 = 0x0000007B (1.723597e-43)
697 splat_4_constants              $32..35 = 0x0000007B (1.723597e-43)
698 splat_4_constants              $36..39 = 0x0000007B (1.723597e-43)
699 bitwise_and_imm_int            $39 &= 0x0000007B
700 bitwise_xor_2_ints             $36..37 ^= $38..39
701 bitwise_or_3_ints              $32..34 |= $35..37
702 add_2_ints                     $31..32 += $33..34
703 sub_3_ints                     $27..29 -= $30..32
704 mul_4_ints                     $22..25 *= $26..29
705 div_n_ints                     $16..20 /= $21..25
706 max_4_ints                     $13..16 = max($13..16, $17..20)
707 min_3_ints                     $11..13 = min($11..13, $14..16)
708 cmplt_int                      $12 = lessThan($12, $13)
709 cmple_2_ints                   $9..10 = lessThanEqual($9..10, $11..12)
710 cmpeq_3_ints                   $5..7 = equal($5..7, $8..10)
711 cmpne_4_ints                   $0..3 = notEqual($0..3, $4..7)
712 )");
713 }
714 
DEF_TEST(RasterPipelineBuilderBinaryUIntOps,r)715 DEF_TEST(RasterPipelineBuilderBinaryUIntOps, r) {
716     using BuilderOp = SkSL::RP::BuilderOp;
717 
718     SkSL::RP::Builder builder;
719     builder.push_constant_u(456);
720     builder.push_duplicates(21);
721     builder.binary_op(BuilderOp::div_n_uints, 6);
722     builder.binary_op(BuilderOp::cmplt_n_uints, 5);
723     builder.binary_op(BuilderOp::cmple_n_uints, 4);
724     builder.binary_op(BuilderOp::max_n_uints, 3);
725     builder.binary_op(BuilderOp::min_n_uints, 2);
726     builder.discard_stack(2);
727     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/0,
728                                                                 /*numUniformSlots=*/0,
729                                                                 /*numImmutableSlots=*/0);
730     check(r, *program,
731 R"(splat_4_constants              $0..3 = 0x000001C8 (6.389921e-43)
732 splat_4_constants              $4..7 = 0x000001C8 (6.389921e-43)
733 splat_4_constants              $8..11 = 0x000001C8 (6.389921e-43)
734 splat_4_constants              $12..15 = 0x000001C8 (6.389921e-43)
735 splat_4_constants              $16..19 = 0x000001C8 (6.389921e-43)
736 splat_2_constants              $20..21 = 0x000001C8 (6.389921e-43)
737 div_n_uints                    $10..15 /= $16..21
738 cmplt_n_uints                  $6..10 = lessThan($6..10, $11..15)
739 cmple_4_uints                  $3..6 = lessThanEqual($3..6, $7..10)
740 max_3_uints                    $1..3 = max($1..3, $4..6)
741 min_2_uints                    $0..1 = min($0..1, $2..3)
742 )");
743 }
744 
DEF_TEST(RasterPipelineBuilderUnaryOps,r)745 DEF_TEST(RasterPipelineBuilderUnaryOps, r) {
746     using BuilderOp = SkSL::RP::BuilderOp;
747 
748     SkSL::RP::Builder builder;
749     builder.push_constant_i(456);
750     builder.push_duplicates(4);
751     builder.unary_op(BuilderOp::cast_to_float_from_int, 1);
752     builder.unary_op(BuilderOp::cast_to_float_from_uint, 2);
753     builder.unary_op(BuilderOp::cast_to_int_from_float, 3);
754     builder.unary_op(BuilderOp::cast_to_uint_from_float, 4);
755     builder.unary_op(BuilderOp::cos_float, 4);
756     builder.unary_op(BuilderOp::tan_float, 3);
757     builder.unary_op(BuilderOp::sin_float, 2);
758     builder.unary_op(BuilderOp::sqrt_float, 1);
759     builder.unary_op(BuilderOp::abs_int, 2);
760     builder.unary_op(BuilderOp::floor_float, 3);
761     builder.unary_op(BuilderOp::ceil_float, 4);
762     builder.discard_stack(5);
763     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/0,
764                                                                 /*numUniformSlots=*/0,
765                                                                 /*numImmutableSlots=*/0);
766     check(r, *program,
767 R"(splat_4_constants              $0..3 = 0x000001C8 (6.389921e-43)
768 copy_constant                  $4 = 0x000001C8 (6.389921e-43)
769 cast_to_float_from_int         $4 = IntToFloat($4)
770 cast_to_float_from_2_uints     $3..4 = UintToFloat($3..4)
771 cast_to_int_from_3_floats      $2..4 = FloatToInt($2..4)
772 cast_to_uint_from_4_floats     $1..4 = FloatToUint($1..4)
773 cos_float                      $1 = cos($1)
774 cos_float                      $2 = cos($2)
775 cos_float                      $3 = cos($3)
776 cos_float                      $4 = cos($4)
777 tan_float                      $2 = tan($2)
778 tan_float                      $3 = tan($3)
779 tan_float                      $4 = tan($4)
780 sin_float                      $3 = sin($3)
781 sin_float                      $4 = sin($4)
782 sqrt_float                     $4 = sqrt($4)
783 abs_2_ints                     $3..4 = abs($3..4)
784 floor_3_floats                 $2..4 = floor($2..4)
785 ceil_4_floats                  $1..4 = ceil($1..4)
786 )");
787 }
788 
DEF_TEST(RasterPipelineBuilderUniforms,r)789 DEF_TEST(RasterPipelineBuilderUniforms, r) {
790     using BuilderOp = SkSL::RP::BuilderOp;
791 
792     // Create a very simple nonsense program.
793     SkSL::RP::Builder builder;
794     builder.push_uniform(one_slot_at(0));        // push into 0
795     builder.push_uniform(two_slots_at(1));       // push into 1~2
796     builder.push_uniform(three_slots_at(3));     // push into 3~5
797     builder.push_uniform(four_slots_at(6));      // push into 6~9
798     builder.push_uniform(five_slots_at(0));      // push into 10~14
799     builder.unary_op(BuilderOp::abs_int, 1);     // perform work so the program isn't eliminated
800     builder.discard_stack(15);                   // balance stack
801     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/0,
802                                                                 /*numUniformSlots=*/10,
803                                                                 /*numImmutableSlots=*/0);
804     check(r, *program,
805 R"(copy_4_uniforms                $0..3 = u0..3
806 copy_4_uniforms                $4..7 = u4..7
807 copy_2_uniforms                $8..9 = u8..9
808 copy_4_uniforms                $10..13 = u0..3
809 copy_uniform                   $14 = u4
810 abs_int                        $14 = abs($14)
811 )");
812 }
813 
DEF_TEST(RasterPipelineBuilderPushZeros,r)814 DEF_TEST(RasterPipelineBuilderPushZeros, r) {
815     using BuilderOp = SkSL::RP::BuilderOp;
816 
817     // Create a very simple nonsense program.
818     SkSL::RP::Builder builder;
819     builder.push_zeros(1);                    // push into 0
820     builder.push_zeros(2);                    // push into 1~2
821     builder.push_zeros(3);                    // push into 3~5
822     builder.push_zeros(4);                    // push into 6~9
823     builder.push_zeros(5);                    // push into 10~14
824     builder.unary_op(BuilderOp::abs_int, 1);  // perform work so the program isn't eliminated
825     builder.discard_stack(15);                // balance stack
826     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/0,
827                                                                 /*numUniformSlots=*/10,
828                                                                 /*numImmutableSlots=*/0);
829     check(r, *program,
830 R"(splat_4_constants              $0..3 = 0
831 splat_4_constants              $4..7 = 0
832 splat_4_constants              $8..11 = 0
833 splat_3_constants              $12..14 = 0
834 abs_int                        $14 = abs($14)
835 )");
836 }
837 
DEF_TEST(RasterPipelineBuilderTernaryFloatOps,r)838 DEF_TEST(RasterPipelineBuilderTernaryFloatOps, r) {
839     using BuilderOp = SkSL::RP::BuilderOp;
840 
841     SkSL::RP::Builder builder;
842     builder.push_constant_f(0.75f);
843     builder.push_duplicates(8);
844     builder.ternary_op(BuilderOp::mix_n_floats, 3);
845     builder.discard_stack(3);
846     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/0,
847                                                                 /*numUniformSlots=*/0,
848                                                                 /*numImmutableSlots=*/0);
849     check(r, *program,
850 R"(splat_4_constants              $0..3 = 0x3F400000 (0.75)
851 splat_4_constants              $4..7 = 0x3F400000 (0.75)
852 copy_constant                  $8 = 0x3F400000 (0.75)
853 mix_3_floats                   $0..2 = mix($3..5, $6..8, $0..2)
854 )");
855 }
856 
DEF_TEST(RasterPipelineBuilderAutomaticStackRewinding,r)857 DEF_TEST(RasterPipelineBuilderAutomaticStackRewinding, r) {
858     using BuilderOp = SkSL::RP::BuilderOp;
859 
860     SkSL::RP::Builder builder;
861     builder.push_constant_i(1);
862     builder.push_duplicates(2000);
863     builder.unary_op(BuilderOp::abs_int, 1);  // perform work so the program isn't eliminated
864     builder.discard_stack(2001);
865     std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/0,
866                                                                 /*numUniformSlots=*/0,
867                                                                 /*numImmutableSlots=*/0);
868     sk_sp<SkData> dump = get_program_dump(*program);
869 
870 #if SK_HAS_MUSTTAIL
871     // We have guaranteed tail-calling, so we never use `stack_rewind`.
872     REPORTER_ASSERT(r, !skstd::contains(as_string_view(dump), "stack_rewind"));
873 #else
874     // We can't guarantee tail-calling, so we should automatically insert `stack_rewind` stages into
875     // long programs.
876     REPORTER_ASSERT(r, skstd::contains(as_string_view(dump), "stack_rewind"));
877 #endif
878 }
879 
DEF_TEST(RasterPipelineBuilderTraceOps,r)880 DEF_TEST(RasterPipelineBuilderTraceOps, r) {
881     for (bool provideDebugTrace : {false, true}) {
882         SkSL::RP::Builder builder;
883         // Create a trace mask stack on stack-ID 123.
884         builder.set_current_stack(123);
885         builder.push_constant_i(~0);
886         // Emit trace ops.
887         builder.trace_enter(123, 2);
888         builder.trace_scope(123, +1);
889         builder.trace_line(123, 456);
890         builder.trace_var(123, two_slots_at(3));
891         builder.trace_scope(123, -1);
892         builder.trace_exit(123, 2);
893         // Discard the trace mask.
894         builder.discard_stack(1);
895 
896         if (!provideDebugTrace) {
897             // Test the output when no DebugTrace info is provided.
898             std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/20,
899                                                                         /*numUniformSlots=*/0,
900                                                                         /*numImmutableSlots=*/0);
901             check(r, *program,
902 R"(copy_constant                  $0 = 0xFFFFFFFF
903 trace_enter                    TraceEnter(???) when $0 is true
904 trace_scope                    TraceScope(+1) when $0 is true
905 trace_line                     TraceLine(456) when $0 is true
906 trace_var                      TraceVar(v3..4) when $0 is true
907 trace_scope                    TraceScope(-1) when $0 is true
908 trace_exit                     TraceExit(???) when $0 is true
909 )");
910         } else {
911             // Test the output when we supply a populated DebugTrace.
912             SkSL::DebugTracePriv trace;
913             trace.fFuncInfo = {{"FunctionA"}, {"FunctionB"}, {"FunctionC"}, {"FunctionD"}};
914 
915             SkSL::SlotDebugInfo slot;
916             slot.name = "Var0";
917             trace.fSlotInfo.push_back(slot);
918             slot.name = "Var1";
919             trace.fSlotInfo.push_back(slot);
920             slot.name = "Var2";
921             trace.fSlotInfo.push_back(slot);
922             slot.name = "Var3";
923             trace.fSlotInfo.push_back(slot);
924             slot.name = "Var4";
925             trace.fSlotInfo.push_back(slot);
926 
927             std::unique_ptr<SkSL::RP::Program> program = builder.finish(/*numValueSlots=*/20,
928                                                                         /*numUniformSlots=*/0,
929                                                                         /*numImmutableSlots=*/0,
930                                                                         &trace);
931             check(r, *program,
932 R"(copy_constant                  $0 = 0xFFFFFFFF
933 trace_enter                    TraceEnter(FunctionC) when $0 is true
934 trace_scope                    TraceScope(+1) when $0 is true
935 trace_line                     TraceLine(456) when $0 is true
936 trace_var                      TraceVar(Var3, Var4) when $0 is true
937 trace_scope                    TraceScope(-1) when $0 is true
938 trace_exit                     TraceExit(FunctionC) when $0 is true
939 )");
940         }
941     }
942 }
943