Flutter Engine
The Flutter Engine
Classes | Public Member Functions | List of all members
SkSL::RP::Builder Class Reference

#include <SkSLRasterPipelineBuilder.h>

Public Member Functions

std::unique_ptr< Programfinish (int numValueSlots, int numUniformSlots, int numImmutableSlots, DebugTracePriv *debugTrace=nullptr)
 
int nextLabelID ()
 
void enableExecutionMaskWrites ()
 
void disableExecutionMaskWrites ()
 
bool executionMaskWritesAreEnabled ()
 
void init_lane_masks ()
 
void store_src_rg (SlotRange slots)
 
void store_src (SlotRange slots)
 
void store_dst (SlotRange slots)
 
void store_device_xy01 (SlotRange slots)
 
void load_src (SlotRange slots)
 
void load_dst (SlotRange slots)
 
void set_current_stack (int stackID)
 
void label (int labelID)
 
void jump (int labelID)
 
void branch_if_all_lanes_active (int labelID)
 
void branch_if_any_lanes_active (int labelID)
 
void branch_if_no_lanes_active (int labelID)
 
void branch_if_no_active_lanes_on_stack_top_equal (int value, int labelID)
 
void push_constant_i (int32_t val, int count=1)
 
void push_zeros (int count)
 
void push_constant_f (float val)
 
void push_constant_u (uint32_t val, int count=1)
 
void push_uniform (SlotRange src)
 
void store_immutable_value_i (Slot slot, int32_t val)
 
void copy_uniform_to_slots_unmasked (SlotRange dst, SlotRange src)
 
void push_uniform_indirect (SlotRange fixedRange, int dynamicStack, SlotRange limitRange)
 
void push_slots (SlotRange src)
 
void push_immutable (SlotRange src)
 
void push_slots_or_immutable (SlotRange src, BuilderOp op)
 
void push_slots_indirect (SlotRange fixedRange, int dynamicStack, SlotRange limitRange)
 
void push_immutable_indirect (SlotRange fixedRange, int dynamicStack, SlotRange limitRange)
 
void push_slots_or_immutable_indirect (SlotRange fixedRange, int dynamicStack, SlotRange limitRange, BuilderOp op)
 
void copy_stack_to_slots (SlotRange dst)
 
void copy_stack_to_slots (SlotRange dst, int offsetFromStackTop)
 
void swizzle_copy_stack_to_slots (SlotRange dst, SkSpan< const int8_t > components, int offsetFromStackTop)
 
void swizzle_copy_stack_to_slots_indirect (SlotRange fixedRange, int dynamicStackID, SlotRange limitRange, SkSpan< const int8_t > components, int offsetFromStackTop)
 
void copy_stack_to_slots_unmasked (SlotRange dst)
 
void copy_stack_to_slots_unmasked (SlotRange dst, int offsetFromStackTop)
 
void copy_stack_to_slots_indirect (SlotRange fixedRange, int dynamicStackID, SlotRange limitRange)
 
void pop_slots_indirect (SlotRange fixedRange, int dynamicStackID, SlotRange limitRange)
 
void unary_op (BuilderOp op, int32_t slots)
 
void binary_op (BuilderOp op, int32_t slots)
 
void ternary_op (BuilderOp op, int32_t slots)
 
void dot_floats (int32_t slots)
 
void refract_floats ()
 
void inverse_matrix (int32_t n)
 
void discard_stack (int32_t count, int stackID)
 
void discard_stack (int32_t count)
 
void pad_stack (int32_t count)
 
void pop_slots (SlotRange dst)
 
void push_duplicates (int count)
 
void push_clone (int numSlots, int offsetFromStackTop=0)
 
void push_clone_from_stack (SlotRange range, int otherStackID, int offsetFromStackTop)
 
void push_clone_indirect_from_stack (SlotRange fixedOffset, int dynamicStackID, int otherStackID, int offsetFromStackTop)
 
void case_op (int value)
 
void continue_op (int continueMaskStackID)
 
void select (int slots)
 
void pop_slots_unmasked (SlotRange dst)
 
void copy_slots_masked (SlotRange dst, SlotRange src)
 
void copy_slots_unmasked (SlotRange dst, SlotRange src)
 
void copy_immutable_unmasked (SlotRange dst, SlotRange src)
 
void copy_constant (Slot slot, int constantValue)
 
void zero_slots_unmasked (SlotRange dst)
 
void swizzle (int consumedSlots, SkSpan< const int8_t > components)
 
void transpose (int columns, int rows)
 
void diagonal_matrix (int columns, int rows)
 
void matrix_resize (int origColumns, int origRows, int newColumns, int newRows)
 
void matrix_multiply (int leftColumns, int leftRows, int rightColumns, int rightRows)
 
void push_condition_mask ()
 
void pop_condition_mask ()
 
void merge_condition_mask ()
 
void merge_inv_condition_mask ()
 
void push_loop_mask ()
 
void pop_loop_mask ()
 
void exchange_src ()
 
void push_src_rgba ()
 
void push_dst_rgba ()
 
void push_device_xy01 ()
 
void pop_src_rgba ()
 
void pop_dst_rgba ()
 
void mask_off_loop_mask ()
 
void reenable_loop_mask (SlotRange src)
 
void pop_and_reenable_loop_mask ()
 
void merge_loop_mask ()
 
void push_return_mask ()
 
void pop_return_mask ()
 
void mask_off_return_mask ()
 
void invoke_shader (int childIdx)
 
void invoke_color_filter (int childIdx)
 
void invoke_blender (int childIdx)
 
void invoke_to_linear_srgb ()
 
void invoke_from_linear_srgb ()
 
void trace_line (int traceMaskStackID, int line)
 
void trace_var (int traceMaskStackID, SlotRange r)
 
void trace_var_indirect (int traceMaskStackID, SlotRange fixedRange, int dynamicStackID, SlotRange limitRange)
 
void trace_enter (int traceMaskStackID, int funcID)
 
void trace_exit (int traceMaskStackID, int funcID)
 
void trace_scope (int traceMaskStackID, int delta)
 

Detailed Description

Definition at line 294 of file SkSLRasterPipelineBuilder.h.

Member Function Documentation

◆ binary_op()

void SkSL::RP::Builder::binary_op ( BuilderOp  op,
int32_t  slots 
)

Definition at line 222 of file SkSLRasterPipelineBuilder.cpp.

222 {
223 if (Instruction* lastInstruction = this->lastInstruction()) {
224 // If we just pushed or splatted a constant onto the stack...
225 if (lastInstruction->fOp == BuilderOp::push_constant &&
226 lastInstruction->fImmA >= slots) {
227 // ... and this op has an immediate-mode equivalent...
228 int32_t constantValue = lastInstruction->fImmB;
229 BuilderOp immOp = convert_n_way_op_to_immediate(op, slots, &constantValue);
230 if (immOp != op) {
231 // ... discard the constants from the stack, and use an immediate-mode op.
232 this->discard_stack(slots);
233 this->appendInstruction(immOp, {}, slots, constantValue);
234 return;
235 }
236 }
237 }
238
239 switch (op) {
242 this->appendInstruction(op, {}, slots);
243 break;
244
245 default:
246 SkDEBUGFAIL("not a binary op");
247 break;
248 }
249}
#define SkDEBUGFAIL(message)
Definition: SkAssert.h:118
#define ALL_N_WAY_BINARY_OP_CASES
#define ALL_MULTI_SLOT_BINARY_OP_CASES
void discard_stack(int32_t count, int stackID)
static BuilderOp convert_n_way_op_to_immediate(BuilderOp op, int slots, int32_t *constantValue)

◆ branch_if_all_lanes_active()

void SkSL::RP::Builder::branch_if_all_lanes_active ( int  labelID)

Definition at line 484 of file SkSLRasterPipelineBuilder.cpp.

484 {
485 if (!this->executionMaskWritesAreEnabled()) {
486 this->jump(labelID);
487 return;
488 }
489
490 SkASSERT(labelID >= 0 && labelID < fNumLabels);
491 if (const Instruction* lastInstruction = this->lastInstructionOnAnyStack()) {
492 if (lastInstruction->fOp == BuilderOp::branch_if_all_lanes_active ||
493 lastInstruction->fOp == BuilderOp::jump) {
494 // The previous instruction was `jump` or `branch_if_all_lanes_active`, so this branch
495 // could never possibly occur.
496 return;
497 }
498 }
499 this->appendInstruction(BuilderOp::branch_if_all_lanes_active, {}, labelID);
500}
#define SkASSERT(cond)
Definition: SkAssert.h:116

◆ branch_if_any_lanes_active()

void SkSL::RP::Builder::branch_if_any_lanes_active ( int  labelID)

Definition at line 466 of file SkSLRasterPipelineBuilder.cpp.

466 {
467 if (!this->executionMaskWritesAreEnabled()) {
468 this->jump(labelID);
469 return;
470 }
471
472 SkASSERT(labelID >= 0 && labelID < fNumLabels);
473 if (const Instruction* lastInstruction = this->lastInstructionOnAnyStack()) {
474 if (lastInstruction->fOp == BuilderOp::branch_if_any_lanes_active ||
475 lastInstruction->fOp == BuilderOp::jump) {
476 // The previous instruction was `jump` or `branch_if_any_lanes_active`, so this branch
477 // could never possibly occur.
478 return;
479 }
480 }
481 this->appendInstruction(BuilderOp::branch_if_any_lanes_active, {}, labelID);
482}

◆ branch_if_no_active_lanes_on_stack_top_equal()

void SkSL::RP::Builder::branch_if_no_active_lanes_on_stack_top_equal ( int  value,
int  labelID 
)

Definition at line 519 of file SkSLRasterPipelineBuilder.cpp.

519 {
520 SkASSERT(labelID >= 0 && labelID < fNumLabels);
521 if (const Instruction* lastInstruction = this->lastInstructionOnAnyStack()) {
522 if (lastInstruction->fOp == BuilderOp::jump ||
524 lastInstruction->fImmB == value)) {
525 // The previous instruction was `jump` or `branch_if_no_active_lanes_on_stack_top_equal`
526 // (checking against the same value), so this branch could never possibly occur.
527 return;
528 }
529 }
531 {}, labelID, value);
532}
uint8_t value
@ branch_if_no_active_lanes_on_stack_top_equal

◆ branch_if_no_lanes_active()

void SkSL::RP::Builder::branch_if_no_lanes_active ( int  labelID)

Definition at line 502 of file SkSLRasterPipelineBuilder.cpp.

502 {
503 if (!this->executionMaskWritesAreEnabled()) {
504 return;
505 }
506
507 SkASSERT(labelID >= 0 && labelID < fNumLabels);
508 if (const Instruction* lastInstruction = this->lastInstructionOnAnyStack()) {
509 if (lastInstruction->fOp == BuilderOp::branch_if_no_lanes_active ||
510 lastInstruction->fOp == BuilderOp::jump) {
511 // The previous instruction was `jump` or `branch_if_no_lanes_active`, so this branch
512 // could never possibly occur.
513 return;
514 }
515 }
516 this->appendInstruction(BuilderOp::branch_if_no_lanes_active, {}, labelID);
517}

◆ case_op()

void SkSL::RP::Builder::case_op ( int  value)
inline

Definition at line 547 of file SkSLRasterPipelineBuilder.h.

547 {
548 this->appendInstruction(BuilderOp::case_op, {}, value);
549 }

◆ continue_op()

void SkSL::RP::Builder::continue_op ( int  continueMaskStackID)
inline

Definition at line 552 of file SkSLRasterPipelineBuilder.h.

552 {
553 this->appendInstruction(BuilderOp::continue_op, {}, continueMaskStackID);
554 }

◆ copy_constant()

void SkSL::RP::Builder::copy_constant ( Slot  slot,
int  constantValue 
)

Definition at line 904 of file SkSLRasterPipelineBuilder.cpp.

904 {
905 // If the last instruction copied the same constant, just extend it.
906 if (Instruction* lastInstr = this->lastInstruction()) {
907 // If the last op is copy-constant...
908 if (lastInstr->fOp == BuilderOp::copy_constant &&
909 // ... and has the same value...
910 lastInstr->fImmB == constantValue &&
911 // ... and the slot is immediately after the last copy-constant's destination...
912 lastInstr->fSlotA + lastInstr->fImmA == slot) {
913 // ... then we can extend the copy!
914 lastInstr->fImmA += 1;
915 return;
916 }
917 }
918
919 this->appendInstruction(BuilderOp::copy_constant, {slot}, 1, constantValue);
920}

◆ copy_immutable_unmasked()

void SkSL::RP::Builder::copy_immutable_unmasked ( SlotRange  dst,
SlotRange  src 
)

Definition at line 944 of file SkSLRasterPipelineBuilder.cpp.

944 {
945 // If the last instruction copied adjacent immutable data, just extend it.
946 if (Instruction* lastInstr = this->lastInstruction()) {
947 // If the last op is a match...
948 if (lastInstr->fOp == BuilderOp::copy_immutable_unmasked &&
949 // and this op's destination is immediately after the last copy-slots-op's destination
950 lastInstr->fSlotA + lastInstr->fImmA == dst.index &&
951 // and this op's source is immediately after the last copy-slots-op's source
952 lastInstr->fSlotB + lastInstr->fImmA == src.index) {
953 // then we can just extend the copy!
954 lastInstr->fImmA += dst.count;
955 return;
956 }
957 }
958
959 SkASSERT(dst.count == src.count);
960 this->appendInstruction(BuilderOp::copy_immutable_unmasked, {dst.index, src.index}, dst.count);
961}
dst
Definition: cp.py:12

◆ copy_slots_masked()

void SkSL::RP::Builder::copy_slots_masked ( SlotRange  dst,
SlotRange  src 
)
inline

Definition at line 567 of file SkSLRasterPipelineBuilder.h.

567 {
568 SkASSERT(dst.count == src.count);
569 this->appendInstruction(BuilderOp::copy_slot_masked, {dst.index, src.index}, dst.count);
570 }

◆ copy_slots_unmasked()

void SkSL::RP::Builder::copy_slots_unmasked ( SlotRange  dst,
SlotRange  src 
)

Definition at line 922 of file SkSLRasterPipelineBuilder.cpp.

922 {
923 // If the last instruction copied adjacent slots, just extend it.
924 if (Instruction* lastInstr = this->lastInstruction()) {
925 // If the last op is a match...
926 if (lastInstr->fOp == BuilderOp::copy_slot_unmasked &&
927 // and this op's destination is immediately after the last copy-slots-op's destination
928 lastInstr->fSlotA + lastInstr->fImmA == dst.index &&
929 // and this op's source is immediately after the last copy-slots-op's source
930 lastInstr->fSlotB + lastInstr->fImmA == src.index &&
931 // and the source/dest ranges will not overlap
932 !slot_ranges_overlap({lastInstr->fSlotB, lastInstr->fImmA + dst.count},
933 {lastInstr->fSlotA, lastInstr->fImmA + dst.count})) {
934 // then we can just extend the copy!
935 lastInstr->fImmA += dst.count;
936 return;
937 }
938 }
939
940 SkASSERT(dst.count == src.count);
941 this->appendInstruction(BuilderOp::copy_slot_unmasked, {dst.index, src.index}, dst.count);
942}
static bool slot_ranges_overlap(SlotRange x, SlotRange y)

◆ copy_stack_to_slots() [1/2]

void SkSL::RP::Builder::copy_stack_to_slots ( SlotRange  dst)
inline

Definition at line 450 of file SkSLRasterPipelineBuilder.h.

450 {
451 this->copy_stack_to_slots(dst, /*offsetFromStackTop=*/dst.count);
452 }
void copy_stack_to_slots(SlotRange dst)

◆ copy_stack_to_slots() [2/2]

void SkSL::RP::Builder::copy_stack_to_slots ( SlotRange  dst,
int  offsetFromStackTop 
)

Definition at line 861 of file SkSLRasterPipelineBuilder.cpp.

861 {
862 // If the execution mask is known to be all-true, then we can ignore the write mask.
863 if (!this->executionMaskWritesAreEnabled()) {
864 this->copy_stack_to_slots_unmasked(dst, offsetFromStackTop);
865 return;
866 }
867
868 // If the last instruction copied the previous stack slots, just extend it.
869 if (Instruction* lastInstruction = this->lastInstruction()) {
870 // If the last op is copy-stack-to-slots...
871 if (lastInstruction->fOp == BuilderOp::copy_stack_to_slots &&
872 // and this op's destination is immediately after the last copy-slots-op's destination
873 lastInstruction->fSlotA + lastInstruction->fImmA == dst.index &&
874 // and this op's source is immediately after the last copy-slots-op's source
875 lastInstruction->fImmB - lastInstruction->fImmA == offsetFromStackTop) {
876 // then we can just extend the copy!
877 lastInstruction->fImmA += dst.count;
878 return;
879 }
880 }
881
882 this->appendInstruction(BuilderOp::copy_stack_to_slots, {dst.index},
883 dst.count, offsetFromStackTop);
884}
void copy_stack_to_slots_unmasked(SlotRange dst)

◆ copy_stack_to_slots_indirect()

void SkSL::RP::Builder::copy_stack_to_slots_indirect ( SlotRange  fixedRange,
int  dynamicStackID,
SlotRange  limitRange 
)

Definition at line 886 of file SkSLRasterPipelineBuilder.cpp.

888 {
889 // SlotA: fixed-range start
890 // SlotB: limit-range end
891 // immA: number of slots
892 // immB: dynamic stack ID
893 this->appendInstruction(BuilderOp::copy_stack_to_slots_indirect,
894 {fixedRange.index, limitRange.index + limitRange.count},
895 fixedRange.count,
896 dynamicStackID);
897}

◆ copy_stack_to_slots_unmasked() [1/2]

void SkSL::RP::Builder::copy_stack_to_slots_unmasked ( SlotRange  dst)
inline

Definition at line 472 of file SkSLRasterPipelineBuilder.h.

472 {
473 this->copy_stack_to_slots_unmasked(dst, /*offsetFromStackTop=*/dst.count);
474 }

◆ copy_stack_to_slots_unmasked() [2/2]

void SkSL::RP::Builder::copy_stack_to_slots_unmasked ( SlotRange  dst,
int  offsetFromStackTop 
)

Definition at line 983 of file SkSLRasterPipelineBuilder.cpp.

983 {
984 // If the last instruction copied the previous stack slots, just extend it.
985 if (Instruction* lastInstr = this->lastInstruction()) {
986 // If the last op is copy-stack-to-slots-unmasked...
987 if (lastInstr->fOp == BuilderOp::copy_stack_to_slots_unmasked &&
988 // and this op's destination is immediately after the last copy-slots-op's destination
989 lastInstr->fSlotA + lastInstr->fImmA == dst.index &&
990 // and this op's source is immediately after the last copy-slots-op's source
991 lastInstr->fImmB - lastInstr->fImmA == offsetFromStackTop) {
992 // then we can just extend the copy!
993 lastInstr->fImmA += dst.count;
994 return;
995 }
996 }
997
998 this->appendInstruction(BuilderOp::copy_stack_to_slots_unmasked, {dst.index},
999 dst.count, offsetFromStackTop);
1000}

◆ copy_uniform_to_slots_unmasked()

void SkSL::RP::Builder::copy_uniform_to_slots_unmasked ( SlotRange  dst,
SlotRange  src 
)

Definition at line 963 of file SkSLRasterPipelineBuilder.cpp.

963 {
964 // If the last instruction copied adjacent uniforms, just extend it.
965 if (Instruction* lastInstr = this->lastInstruction()) {
966 // If the last op is copy-constant...
967 if (lastInstr->fOp == BuilderOp::copy_uniform_to_slots_unmasked &&
968 // and this op's destination is immediately after the last copy-constant's destination
969 lastInstr->fSlotB + lastInstr->fImmA == dst.index &&
970 // and this op's source is immediately after the last copy-constant's source
971 lastInstr->fSlotA + lastInstr->fImmA == src.index) {
972 // then we can just extend the copy!
973 lastInstr->fImmA += dst.count;
974 return;
975 }
976 }
977
978 SkASSERT(dst.count == src.count);
979 this->appendInstruction(BuilderOp::copy_uniform_to_slots_unmasked, {src.index, dst.index},
980 dst.count);
981}

◆ diagonal_matrix()

void SkSL::RP::Builder::diagonal_matrix ( int  columns,
int  rows 
)

Definition at line 1203 of file SkSLRasterPipelineBuilder.cpp.

1203 {
1204 // Generates a CxR diagonal matrix from the top two scalars on the stack.
1205 int8_t elements[16] = {};
1206 size_t index = 0;
1207 for (int c = 0; c < columns; ++c) {
1208 for (int r = 0; r < rows; ++r) {
1209 elements[index++] = (c == r) ? 1 : 0;
1210 }
1211 }
1212 this->swizzle(/*consumedSlots=*/2, SkSpan(elements, index));
1213}
SkSpan(Container &&) -> SkSpan< std::remove_pointer_t< decltype(std::data(std::declval< Container >()))> >
void swizzle(int consumedSlots, SkSpan< const int8_t > components)

◆ disableExecutionMaskWrites()

void SkSL::RP::Builder::disableExecutionMaskWrites ( )
inline

Definition at line 319 of file SkSLRasterPipelineBuilder.h.

319 {
321 --fExecutionMaskWritesEnabled;
322 }

◆ discard_stack() [1/2]

void SkSL::RP::Builder::discard_stack ( int32_t  count)
inline

Definition at line 518 of file SkSLRasterPipelineBuilder.h.

518 {
519 this->discard_stack(count, fCurrentStackID);
520 }
int count
Definition: FontMgrTest.cpp:50

◆ discard_stack() [2/2]

void SkSL::RP::Builder::discard_stack ( int32_t  count,
int  stackID 
)

Definition at line 340 of file SkSLRasterPipelineBuilder.cpp.

340 {
341 // If we pushed something onto the stack and then immediately discarded part of it, we can
342 // shrink or eliminate the push.
343 while (count > 0) {
344 Instruction* lastInstruction = this->lastInstructionOnAnyStack();
345 if (!lastInstruction || lastInstruction->fStackID != stackID) {
346 break;
347 }
348
349 switch (lastInstruction->fOp) {
351 // Our last op was actually a separate discard_stack; combine the discards.
352 lastInstruction->fImmA += count;
353 return;
354
366 // Our last op was a multi-slot push; these cancel out. Eliminate the op if its
367 // count reached zero.
368 int cancelOut = std::min(count, lastInstruction->fImmA);
369 count -= cancelOut;
370 lastInstruction->fImmA -= cancelOut;
371 if (lastInstruction->fImmA == 0) {
372 fInstructions.pop_back();
373 }
374 continue;
375 }
379 // Our last op was a single-slot push; cancel out one discard and eliminate the op.
380 --count;
381 fInstructions.pop_back();
382 continue;
383
385 // Look for a pattern of `push, immediate-ops, pop` and simplify it down to an
386 // immediate-op directly to the value slot.
387 if (count == 1) {
388 if (this->simplifyImmediateUnmaskedOp()) {
389 return;
390 }
391 }
392
393 // A `copy_stack_to_slots_unmasked` op, followed immediately by a `discard_stack`
394 // op with an equal number of slots, is interpreted as an unmasked stack pop.
395 // We can simplify pops in a variety of ways. First, temporarily get rid of
396 // `copy_stack_to_slots_unmasked`.
397 if (count == lastInstruction->fImmA) {
398 SlotRange dst{lastInstruction->fSlotA, lastInstruction->fImmA};
399 fInstructions.pop_back();
400
401 // See if we can write this pop in a simpler way.
402 this->simplifyPopSlotsUnmasked(&dst);
403
404 // If simplification consumed the entire range, we're done!
405 if (dst.count == 0) {
406 return;
407 }
408
409 // Simplification did not consume the entire range. We are still responsible for
410 // copying-back and discarding any remaining slots.
412 count = dst.count;
413 }
414 break;
415 }
416 default:
417 break;
418 }
419
420 // This instruction wasn't a push.
421 break;
422 }
423
424 if (count > 0) {
425 this->appendInstruction(BuilderOp::discard_stack, {}, count);
426 }
427}
static float min(float r, float g, float b)
Definition: hsl.cpp:48

◆ dot_floats()

void SkSL::RP::Builder::dot_floats ( int32_t  slots)

Definition at line 264 of file SkSLRasterPipelineBuilder.cpp.

264 {
265 switch (slots) {
266 case 1: this->appendInstruction(BuilderOp::mul_n_floats, {}, slots); break;
267 case 2: this->appendInstruction(BuilderOp::dot_2_floats, {}, slots); break;
268 case 3: this->appendInstruction(BuilderOp::dot_3_floats, {}, slots); break;
269 case 4: this->appendInstruction(BuilderOp::dot_4_floats, {}, slots); break;
270
271 default:
272 SkDEBUGFAIL("invalid number of slots");
273 break;
274 }
275}

◆ enableExecutionMaskWrites()

void SkSL::RP::Builder::enableExecutionMaskWrites ( )
inline

The builder keeps track of the state of execution masks; when we know that the execution mask is unaltered, we can generate simpler code. Code which alters the execution mask is required to enable this flag.

Definition at line 315 of file SkSLRasterPipelineBuilder.h.

315 {
316 ++fExecutionMaskWritesEnabled;
317 }

◆ exchange_src()

void SkSL::RP::Builder::exchange_src ( )

Definition at line 834 of file SkSLRasterPipelineBuilder.cpp.

834 {
835 if (Instruction* lastInstruction = this->lastInstruction()) {
836 // If the previous op is also an exchange-src...
837 if (lastInstruction->fOp == BuilderOp::exchange_src) {
838 // ... both ops can be eliminated. A double-swap is a no-op.
839 fInstructions.pop_back();
840 return;
841 }
842 }
843
844 this->appendInstruction(BuilderOp::exchange_src, {});
845}

◆ executionMaskWritesAreEnabled()

bool SkSL::RP::Builder::executionMaskWritesAreEnabled ( )
inline

Definition at line 324 of file SkSLRasterPipelineBuilder.h.

324 {
325 return fExecutionMaskWritesEnabled > 0;
326 }

◆ finish()

std::unique_ptr< Program > SkSL::RP::Builder::finish ( int  numValueSlots,
int  numUniformSlots,
int  numImmutableSlots,
DebugTracePriv debugTrace = nullptr 
)

Finalizes and optimizes the program.

Definition at line 1263 of file SkSLRasterPipelineBuilder.cpp.

1266 {
1267 // Verify that calls to enableExecutionMaskWrites and disableExecutionMaskWrites are balanced.
1268 SkASSERT(fExecutionMaskWritesEnabled == 0);
1269
1270 return std::make_unique<Program>(std::move(fInstructions), numValueSlots, numUniformSlots,
1271 numImmutableSlots, fNumLabels, debugTrace);
1272}

◆ init_lane_masks()

void SkSL::RP::Builder::init_lane_masks ( )
inline

Assemble a program from the Raster Pipeline instructions below.

Definition at line 329 of file SkSLRasterPipelineBuilder.h.

329 {
330 this->appendInstruction(BuilderOp::init_lane_masks, {});
331 }

◆ inverse_matrix()

void SkSL::RP::Builder::inverse_matrix ( int32_t  n)

Definition at line 281 of file SkSLRasterPipelineBuilder.cpp.

281 {
282 switch (n) {
283 case 2: this->appendInstruction(BuilderOp::inverse_mat2, {}, 4); break;
284 case 3: this->appendInstruction(BuilderOp::inverse_mat3, {}, 9); break;
285 case 4: this->appendInstruction(BuilderOp::inverse_mat4, {}, 16); break;
286 default: SkUNREACHABLE;
287 }
288}
#define SkUNREACHABLE
Definition: SkAssert.h:135

◆ invoke_blender()

void SkSL::RP::Builder::invoke_blender ( int  childIdx)
inline

Definition at line 684 of file SkSLRasterPipelineBuilder.h.

684 {
685 this->appendInstruction(BuilderOp::invoke_blender, {}, childIdx);
686 }

◆ invoke_color_filter()

void SkSL::RP::Builder::invoke_color_filter ( int  childIdx)
inline

Definition at line 680 of file SkSLRasterPipelineBuilder.h.

680 {
681 this->appendInstruction(BuilderOp::invoke_color_filter, {}, childIdx);
682 }

◆ invoke_from_linear_srgb()

void SkSL::RP::Builder::invoke_from_linear_srgb ( )
inline

Definition at line 696 of file SkSLRasterPipelineBuilder.h.

696 {
697 // The intrinsics accept a three-component value; add a fourth padding element (which
698 // will be ignored) since our RP ops deal in RGBA colors.
699 this->pad_stack(1);
700 this->appendInstruction(BuilderOp::invoke_from_linear_srgb, {});
701 this->discard_stack(1);
702 }
void pad_stack(int32_t count)

◆ invoke_shader()

void SkSL::RP::Builder::invoke_shader ( int  childIdx)
inline

Definition at line 676 of file SkSLRasterPipelineBuilder.h.

676 {
677 this->appendInstruction(BuilderOp::invoke_shader, {}, childIdx);
678 }

◆ invoke_to_linear_srgb()

void SkSL::RP::Builder::invoke_to_linear_srgb ( )
inline

Definition at line 688 of file SkSLRasterPipelineBuilder.h.

688 {
689 // The intrinsics accept a three-component value; add a fourth padding element (which
690 // will be ignored) since our RP ops deal in RGBA colors.
691 this->pad_stack(1);
692 this->appendInstruction(BuilderOp::invoke_to_linear_srgb, {});
693 this->discard_stack(1);
694 }

◆ jump()

void SkSL::RP::Builder::jump ( int  labelID)

Definition at line 455 of file SkSLRasterPipelineBuilder.cpp.

455 {
456 SkASSERT(labelID >= 0 && labelID < fNumLabels);
457 if (const Instruction* lastInstruction = this->lastInstructionOnAnyStack()) {
458 if (lastInstruction->fOp == BuilderOp::jump) {
459 // The previous instruction was also `jump`, so this branch could never possibly occur.
460 return;
461 }
462 }
463 this->appendInstruction(BuilderOp::jump, {}, labelID);
464}

◆ label()

void SkSL::RP::Builder::label ( int  labelID)

Definition at line 429 of file SkSLRasterPipelineBuilder.cpp.

429 {
430 SkASSERT(labelID >= 0 && labelID < fNumLabels);
431
432 // If the previous instruction was a branch to this label, it's a no-op; jumping to the very
433 // next instruction is effectively meaningless.
434 while (const Instruction* lastInstruction = this->lastInstructionOnAnyStack()) {
435 switch (lastInstruction->fOp) {
436 case BuilderOp::jump:
437 case BuilderOp::branch_if_all_lanes_active:
438 case BuilderOp::branch_if_any_lanes_active:
439 case BuilderOp::branch_if_no_lanes_active:
441 if (lastInstruction->fImmA == labelID) {
442 fInstructions.pop_back();
443 continue;
444 }
445 break;
446
447 default:
448 break;
449 }
450 break;
451 }
452 this->appendInstruction(BuilderOp::label, {}, labelID);
453}

◆ load_dst()

void SkSL::RP::Builder::load_dst ( SlotRange  slots)
inline

Definition at line 358 of file SkSLRasterPipelineBuilder.h.

358 {
359 SkASSERT(slots.count == 4);
360 this->appendInstruction(BuilderOp::load_dst, {slots.index});
361 }

◆ load_src()

void SkSL::RP::Builder::load_src ( SlotRange  slots)
inline

Definition at line 353 of file SkSLRasterPipelineBuilder.h.

353 {
354 SkASSERT(slots.count == 4);
355 this->appendInstruction(BuilderOp::load_src, {slots.index});
356 }

◆ mask_off_loop_mask()

void SkSL::RP::Builder::mask_off_loop_mask ( )
inline

Definition at line 643 of file SkSLRasterPipelineBuilder.h.

643 {
645 this->appendInstruction(BuilderOp::mask_off_loop_mask, {});
646 }

◆ mask_off_return_mask()

void SkSL::RP::Builder::mask_off_return_mask ( )
inline

Definition at line 671 of file SkSLRasterPipelineBuilder.h.

671 {
673 this->appendInstruction(BuilderOp::mask_off_return_mask, {});
674 }

◆ matrix_multiply()

void SkSL::RP::Builder::matrix_multiply ( int  leftColumns,
int  leftRows,
int  rightColumns,
int  rightRows 
)

Definition at line 1251 of file SkSLRasterPipelineBuilder.cpp.

1251 {
1252 BuilderOp op;
1253 switch (leftColumns) {
1254 case 2: op = BuilderOp::matrix_multiply_2; break;
1255 case 3: op = BuilderOp::matrix_multiply_3; break;
1256 case 4: op = BuilderOp::matrix_multiply_4; break;
1257 default: SkDEBUGFAIL("unsupported matrix dimensions"); return;
1258 }
1259
1260 this->appendInstruction(op, {}, leftColumns, leftRows, rightColumns, rightRows);
1261}

◆ matrix_resize()

void SkSL::RP::Builder::matrix_resize ( int  origColumns,
int  origRows,
int  newColumns,
int  newRows 
)

Definition at line 1215 of file SkSLRasterPipelineBuilder.cpp.

1215 {
1216 // Resizes a CxR matrix at the top of the stack to C'xR'.
1217 int8_t elements[16] = {};
1218 size_t index = 0;
1219
1220 size_t consumedSlots = origColumns * origRows;
1221 size_t zeroOffset = 0, oneOffset = 0;
1222
1223 for (int c = 0; c < newColumns; ++c) {
1224 for (int r = 0; r < newRows; ++r) {
1225 if (c < origColumns && r < origRows) {
1226 // Push an element from the original matrix.
1227 elements[index++] = (c * origRows) + r;
1228 } else {
1229 // This element is outside the original matrix; push 1 or 0.
1230 if (c == r) {
1231 // We need to synthesize a literal 1.
1232 if (oneOffset == 0) {
1233 this->push_constant_f(1.0f);
1234 oneOffset = consumedSlots++;
1235 }
1236 elements[index++] = oneOffset;
1237 } else {
1238 // We need to synthesize a literal 0.
1239 if (zeroOffset == 0) {
1240 this->push_constant_f(0.0f);
1241 zeroOffset = consumedSlots++;
1242 }
1243 elements[index++] = zeroOffset;
1244 }
1245 }
1246 }
1247 }
1248 this->swizzle(consumedSlots, SkSpan(elements, index));
1249}

◆ merge_condition_mask()

void SkSL::RP::Builder::merge_condition_mask ( )

Definition at line 1030 of file SkSLRasterPipelineBuilder.cpp.

1030 {
1032
1033 // This instruction is going to overwrite the condition mask. If the previous instruction was
1034 // loading the condition mask, that's wasted work and it can be eliminated.
1035 if (Instruction* lastInstruction = this->lastInstructionOnAnyStack()) {
1036 if (lastInstruction->fOp == BuilderOp::pop_condition_mask) {
1037 int stackID = lastInstruction->fStackID;
1038 fInstructions.pop_back();
1039 this->discard_stack(/*count=*/1, stackID);
1040 }
1041 }
1042
1043 this->appendInstruction(BuilderOp::merge_condition_mask, {});
1044}

◆ merge_inv_condition_mask()

void SkSL::RP::Builder::merge_inv_condition_mask ( )
inline

Definition at line 607 of file SkSLRasterPipelineBuilder.h.

607 {
609 this->appendInstruction(BuilderOp::merge_inv_condition_mask, {});
610 }

◆ merge_loop_mask()

void SkSL::RP::Builder::merge_loop_mask ( )
inline

Definition at line 659 of file SkSLRasterPipelineBuilder.h.

659 {
661 this->appendInstruction(BuilderOp::merge_loop_mask, {});
662 }

◆ nextLabelID()

int SkSL::RP::Builder::nextLabelID ( )
inline

Peels off a label ID for use in the program. Set the label's position in the program with the label instruction. Actually branch to the target with an instruction like branch_if_any_lanes_active or jump.

Definition at line 306 of file SkSLRasterPipelineBuilder.h.

306 {
307 return fNumLabels++;
308 }

◆ pad_stack()

void SkSL::RP::Builder::pad_stack ( int32_t  count)

Definition at line 290 of file SkSLRasterPipelineBuilder.cpp.

290 {
291 if (count > 0) {
292 this->appendInstruction(BuilderOp::pad_stack, {}, count);
293 }
294}

◆ pop_and_reenable_loop_mask()

void SkSL::RP::Builder::pop_and_reenable_loop_mask ( )
inline

Definition at line 654 of file SkSLRasterPipelineBuilder.h.

654 {
656 this->appendInstruction(BuilderOp::pop_and_reenable_loop_mask, {});
657 }

◆ pop_condition_mask()

void SkSL::RP::Builder::pop_condition_mask ( )
inline

Definition at line 600 of file SkSLRasterPipelineBuilder.h.

600 {
602 this->appendInstruction(BuilderOp::pop_condition_mask, {});
603 }

◆ pop_dst_rgba()

void SkSL::RP::Builder::pop_dst_rgba ( )
inline

Definition at line 639 of file SkSLRasterPipelineBuilder.h.

639 {
640 this->appendInstruction(BuilderOp::pop_dst_rgba, {});
641 }

◆ pop_loop_mask()

void SkSL::RP::Builder::pop_loop_mask ( )
inline

Definition at line 617 of file SkSLRasterPipelineBuilder.h.

617 {
619 this->appendInstruction(BuilderOp::pop_loop_mask, {});
620 }

◆ pop_return_mask()

void SkSL::RP::Builder::pop_return_mask ( )

Definition at line 1002 of file SkSLRasterPipelineBuilder.cpp.

1002 {
1004
1005 // This instruction is going to overwrite the return mask. If the previous instruction was
1006 // masking off the return mask, that's wasted work and it can be eliminated.
1007 if (Instruction* lastInstruction = this->lastInstructionOnAnyStack()) {
1008 if (lastInstruction->fOp == BuilderOp::mask_off_return_mask) {
1009 fInstructions.pop_back();
1010 }
1011 }
1012
1013 this->appendInstruction(BuilderOp::pop_return_mask, {});
1014}

◆ pop_slots()

void SkSL::RP::Builder::pop_slots ( SlotRange  dst)

Definition at line 731 of file SkSLRasterPipelineBuilder.cpp.

731 {
732 if (!this->executionMaskWritesAreEnabled()) {
733 this->pop_slots_unmasked(dst);
734 return;
735 }
736
738 this->discard_stack(dst.count);
739}
void pop_slots_unmasked(SlotRange dst)

◆ pop_slots_indirect()

void SkSL::RP::Builder::pop_slots_indirect ( SlotRange  fixedRange,
int  dynamicStackID,
SlotRange  limitRange 
)
inline

Definition at line 487 of file SkSLRasterPipelineBuilder.h.

487 {
488 this->copy_stack_to_slots_indirect(fixedRange, dynamicStackID, limitRange);
489 this->discard_stack(fixedRange.count);
490 }
void copy_stack_to_slots_indirect(SlotRange fixedRange, int dynamicStackID, SlotRange limitRange)

◆ pop_slots_unmasked()

void SkSL::RP::Builder::pop_slots_unmasked ( SlotRange  dst)

Definition at line 828 of file SkSLRasterPipelineBuilder.cpp.

828 {
829 SkASSERT(dst.count >= 0);
831 this->discard_stack(dst.count);
832}

◆ pop_src_rgba()

void SkSL::RP::Builder::pop_src_rgba ( )

Definition at line 847 of file SkSLRasterPipelineBuilder.cpp.

847 {
848 if (Instruction* lastInstruction = this->lastInstruction()) {
849 // If the previous op is exchanging src.rgba with the stack...
850 if (lastInstruction->fOp == BuilderOp::exchange_src) {
851 // ... both ops can be eliminated. It's just sliding the color back and forth.
852 fInstructions.pop_back();
853 this->discard_stack(4);
854 return;
855 }
856 }
857
858 this->appendInstruction(BuilderOp::pop_src_rgba, {});
859}

◆ push_clone()

void SkSL::RP::Builder::push_clone ( int  numSlots,
int  offsetFromStackTop = 0 
)

Definition at line 679 of file SkSLRasterPipelineBuilder.cpp.

679 {
680 // If we are cloning the stack top...
681 if (numSlots == 1 && offsetFromStackTop == 0) {
682 // ... and the previous op is pushing a constant...
683 if (Instruction* lastInstruction = this->lastInstruction()) {
684 if (lastInstruction->fOp == BuilderOp::push_constant) {
685 // ... we can just push more of them.
686 lastInstruction->fImmA += 1;
687 return;
688 }
689 }
690 }
691 this->appendInstruction(BuilderOp::push_clone, {}, numSlots, numSlots + offsetFromStackTop);
692}

◆ push_clone_from_stack()

void SkSL::RP::Builder::push_clone_from_stack ( SlotRange  range,
int  otherStackID,
int  offsetFromStackTop 
)

Definition at line 694 of file SkSLRasterPipelineBuilder.cpp.

694 {
695 // immA: number of slots
696 // immB: other stack ID
697 // immC: offset from stack top
698 offsetFromStackTop -= range.index;
699
700 if (Instruction* lastInstruction = this->lastInstruction()) {
701 // If the previous op is also pushing a clone...
702 if (lastInstruction->fOp == BuilderOp::push_clone_from_stack &&
703 // ... from the same stack...
704 lastInstruction->fImmB == otherStackID &&
705 // ... and this clone starts at the same place that the last clone ends...
706 lastInstruction->fImmC - lastInstruction->fImmA == offsetFromStackTop) {
707 // ... just extend the existing clone-op.
708 lastInstruction->fImmA += range.count;
709 return;
710 }
711 }
712
713 this->appendInstruction(BuilderOp::push_clone_from_stack, {},
714 range.count, otherStackID, offsetFromStackTop);
715}

◆ push_clone_indirect_from_stack()

void SkSL::RP::Builder::push_clone_indirect_from_stack ( SlotRange  fixedOffset,
int  dynamicStackID,
int  otherStackID,
int  offsetFromStackTop 
)

Definition at line 717 of file SkSLRasterPipelineBuilder.cpp.

720 {
721 // immA: number of slots
722 // immB: other stack ID
723 // immC: offset from stack top
724 // immD: dynamic stack ID
725 offsetFromStackTop -= fixedOffset.index;
726
727 this->appendInstruction(BuilderOp::push_clone_indirect_from_stack, {},
728 fixedOffset.count, otherStackID, offsetFromStackTop, dynamicStackID);
729}

◆ push_condition_mask()

void SkSL::RP::Builder::push_condition_mask ( )

Definition at line 1016 of file SkSLRasterPipelineBuilder.cpp.

1016 {
1018
1019 // If the previous instruction is popping the condition mask, we can restore it onto the stack
1020 // "for free" instead of copying it.
1021 if (Instruction* lastInstruction = this->lastInstruction()) {
1022 if (lastInstruction->fOp == BuilderOp::pop_condition_mask) {
1023 this->pad_stack(1);
1024 return;
1025 }
1026 }
1027 this->appendInstruction(BuilderOp::push_condition_mask, {});
1028}

◆ push_constant_f()

void SkSL::RP::Builder::push_constant_f ( float  val)
inline

Definition at line 392 of file SkSLRasterPipelineBuilder.h.

392 {
393 this->push_constant_i(sk_bit_cast<int32_t>(val), /*count=*/1);
394 }
void push_constant_i(int32_t val, int count=1)

◆ push_constant_i()

void SkSL::RP::Builder::push_constant_i ( int32_t  val,
int  count = 1 
)

Definition at line 638 of file SkSLRasterPipelineBuilder.cpp.

638 {
639 SkASSERT(count >= 0);
640 if (count > 0) {
641 if (Instruction* lastInstruction = this->lastInstruction()) {
642 // If the previous op is pushing the same value, we can just push more of them.
643 if (lastInstruction->fOp == BuilderOp::push_constant && lastInstruction->fImmB == val) {
644 lastInstruction->fImmA += count;
645 return;
646 }
647 }
648 this->appendInstruction(BuilderOp::push_constant, {}, count, val);
649 }
650}

◆ push_constant_u()

void SkSL::RP::Builder::push_constant_u ( uint32_t  val,
int  count = 1 
)
inline

Definition at line 396 of file SkSLRasterPipelineBuilder.h.

396 {
397 this->push_constant_i(sk_bit_cast<int32_t>(val), count);
398 }

◆ push_device_xy01()

void SkSL::RP::Builder::push_device_xy01 ( )
inline

Definition at line 633 of file SkSLRasterPipelineBuilder.h.

633 {
634 this->appendInstruction(BuilderOp::push_device_xy01, {});
635 }

◆ push_dst_rgba()

void SkSL::RP::Builder::push_dst_rgba ( )
inline

Definition at line 629 of file SkSLRasterPipelineBuilder.h.

629 {
630 this->appendInstruction(BuilderOp::push_dst_rgba, {});
631 }

◆ push_duplicates()

void SkSL::RP::Builder::push_duplicates ( int  count)

Definition at line 652 of file SkSLRasterPipelineBuilder.cpp.

652 {
653 if (Instruction* lastInstruction = this->lastInstruction()) {
654 // If the previous op is pushing a constant, we can just push more of them.
655 if (lastInstruction->fOp == BuilderOp::push_constant) {
656 lastInstruction->fImmA += count;
657 return;
658 }
659 }
660 SkASSERT(count >= 0);
661 if (count >= 3) {
662 // Use a swizzle to splat the input into a 4-slot value.
663 this->swizzle(/*consumedSlots=*/1, {0, 0, 0, 0});
664 count -= 3;
665 }
666 for (; count >= 4; count -= 4) {
667 // Clone the splatted value four slots at a time.
668 this->push_clone(/*numSlots=*/4);
669 }
670 // Use a swizzle or clone to handle the trailing items.
671 switch (count) {
672 case 3: this->swizzle(/*consumedSlots=*/1, {0, 0, 0, 0}); break;
673 case 2: this->swizzle(/*consumedSlots=*/1, {0, 0, 0}); break;
674 case 1: this->push_clone(/*numSlots=*/1); break;
675 default: break;
676 }
677}
void push_clone(int numSlots, int offsetFromStackTop=0)

◆ push_immutable()

void SkSL::RP::Builder::push_immutable ( SlotRange  src)
inline

Definition at line 425 of file SkSLRasterPipelineBuilder.h.

425 {
427 }
void push_slots_or_immutable(SlotRange src, BuilderOp op)

◆ push_immutable_indirect()

void SkSL::RP::Builder::push_immutable_indirect ( SlotRange  fixedRange,
int  dynamicStack,
SlotRange  limitRange 
)
inline

Definition at line 440 of file SkSLRasterPipelineBuilder.h.

440 {
441 this->push_slots_or_immutable_indirect(fixedRange, dynamicStack, limitRange,
443 }
void push_slots_or_immutable_indirect(SlotRange fixedRange, int dynamicStack, SlotRange limitRange, BuilderOp op)

◆ push_loop_mask()

void SkSL::RP::Builder::push_loop_mask ( )
inline

Definition at line 612 of file SkSLRasterPipelineBuilder.h.

612 {
614 this->appendInstruction(BuilderOp::push_loop_mask, {});
615 }

◆ push_return_mask()

void SkSL::RP::Builder::push_return_mask ( )
inline

Definition at line 664 of file SkSLRasterPipelineBuilder.h.

664 {
666 this->appendInstruction(BuilderOp::push_return_mask, {});
667 }

◆ push_slots()

void SkSL::RP::Builder::push_slots ( SlotRange  src)
inline

Definition at line 420 of file SkSLRasterPipelineBuilder.h.

◆ push_slots_indirect()

void SkSL::RP::Builder::push_slots_indirect ( SlotRange  fixedRange,
int  dynamicStack,
SlotRange  limitRange 
)
inline

Definition at line 435 of file SkSLRasterPipelineBuilder.h.

435 {
436 this->push_slots_or_immutable_indirect(fixedRange, dynamicStack, limitRange,
438 }

◆ push_slots_or_immutable()

void SkSL::RP::Builder::push_slots_or_immutable ( SlotRange  src,
BuilderOp  op 
)

Definition at line 534 of file SkSLRasterPipelineBuilder.cpp.

534 {
535 SkASSERT(src.count >= 0);
536 if (Instruction* lastInstruction = this->lastInstruction()) {
537 // If the previous instruction was pushing slots contiguous to this range, we can collapse
538 // the two pushes into one larger push.
539 if (lastInstruction->fOp == op &&
540 lastInstruction->fSlotA + lastInstruction->fImmA == src.index) {
541 lastInstruction->fImmA += src.count;
542 src.count = 0;
543 }
544 }
545
546 if (src.count > 0) {
547 this->appendInstruction(op, {src.index}, src.count);
548 }
549
550 // Look for a sequence of "copy stack to X, discard stack, copy X to stack". This is a common
551 // pattern when multiple operations in a row affect the same variable. When we see this, we can
552 // eliminate both the discard and the push.
553 if (fInstructions.size() >= 3) {
554 const Instruction* pushInst = this->lastInstruction(/*fromBack=*/0);
555 const Instruction* discardInst = this->lastInstruction(/*fromBack=*/1);
556 const Instruction* copyToSlotsInst = this->lastInstruction(/*fromBack=*/2);
557
558 if (pushInst && discardInst && copyToSlotsInst && pushInst->fOp == BuilderOp::push_slots) {
559 int pushIndex = pushInst->fSlotA;
560 int pushCount = pushInst->fImmA;
561
562 // Look for a `discard_stack` matching our push count.
563 if (discardInst->fOp == BuilderOp::discard_stack && discardInst->fImmA == pushCount) {
564 // Look for a `copy_stack_to_slots` matching our push.
565 if ((copyToSlotsInst->fOp == BuilderOp::copy_stack_to_slots ||
566 copyToSlotsInst->fOp == BuilderOp::copy_stack_to_slots_unmasked) &&
567 copyToSlotsInst->fSlotA == pushIndex && copyToSlotsInst->fImmA == pushCount) {
568 // We found a matching sequence. Remove the discard and push.
569 fInstructions.pop_back();
570 fInstructions.pop_back();
571 return;
572 }
573 }
574 }
575 }
576}

◆ push_slots_or_immutable_indirect()

void SkSL::RP::Builder::push_slots_or_immutable_indirect ( SlotRange  fixedRange,
int  dynamicStack,
SlotRange  limitRange,
BuilderOp  op 
)

Definition at line 578 of file SkSLRasterPipelineBuilder.cpp.

581 {
582 // SlotA: fixed-range start
583 // SlotB: limit-range end
584 // immA: number of slots
585 // immB: dynamic stack ID
586 this->appendInstruction(op,
587 {fixedRange.index, limitRange.index + limitRange.count},
588 fixedRange.count,
589 dynamicStackID);
590}

◆ push_src_rgba()

void SkSL::RP::Builder::push_src_rgba ( )
inline

Definition at line 625 of file SkSLRasterPipelineBuilder.h.

625 {
626 this->appendInstruction(BuilderOp::push_src_rgba, {});
627 }

◆ push_uniform()

void SkSL::RP::Builder::push_uniform ( SlotRange  src)

Definition at line 592 of file SkSLRasterPipelineBuilder.cpp.

592 {
593 SkASSERT(src.count >= 0);
594 if (Instruction* lastInstruction = this->lastInstruction()) {
595 // If the previous instruction was pushing uniforms contiguous to this range, we can
596 // collapse the two pushes into one larger push.
597 if (lastInstruction->fOp == BuilderOp::push_uniform &&
598 lastInstruction->fSlotA + lastInstruction->fImmA == src.index) {
599 lastInstruction->fImmA += src.count;
600 return;
601 }
602 }
603
604 if (src.count > 0) {
605 this->appendInstruction(BuilderOp::push_uniform, {src.index}, src.count);
606 }
607}

◆ push_uniform_indirect()

void SkSL::RP::Builder::push_uniform_indirect ( SlotRange  fixedRange,
int  dynamicStack,
SlotRange  limitRange 
)

Definition at line 609 of file SkSLRasterPipelineBuilder.cpp.

611 {
612 // SlotA: fixed-range start
613 // SlotB: limit-range end
614 // immA: number of slots
615 // immB: dynamic stack ID
616 this->appendInstruction(BuilderOp::push_uniform_indirect,
617 {fixedRange.index, limitRange.index + limitRange.count},
618 fixedRange.count,
619 dynamicStackID);
620}

◆ push_zeros()

void SkSL::RP::Builder::push_zeros ( int  count)
inline

Definition at line 388 of file SkSLRasterPipelineBuilder.h.

388 {
389 this->push_constant_i(/*val=*/0, count);
390 }

◆ reenable_loop_mask()

void SkSL::RP::Builder::reenable_loop_mask ( SlotRange  src)
inline

Definition at line 648 of file SkSLRasterPipelineBuilder.h.

648 {
650 SkASSERT(src.count == 1);
651 this->appendInstruction(BuilderOp::reenable_loop_mask, {src.index});
652 }

◆ refract_floats()

void SkSL::RP::Builder::refract_floats ( )

Definition at line 277 of file SkSLRasterPipelineBuilder.cpp.

277 {
278 this->appendInstruction(BuilderOp::refract_4_floats, {});
279}

◆ select()

void SkSL::RP::Builder::select ( int  slots)
inline

Definition at line 556 of file SkSLRasterPipelineBuilder.h.

556 {
557 // Overlays the top two entries on the stack, making one hybrid entry. The execution mask
558 // is used to select which lanes are preserved.
559 SkASSERT(slots > 0);
560 this->appendInstruction(BuilderOp::select, {}, slots);
561 }

◆ set_current_stack()

void SkSL::RP::Builder::set_current_stack ( int  stackID)
inline

Definition at line 363 of file SkSLRasterPipelineBuilder.h.

363 {
364 fCurrentStackID = stackID;
365 }

◆ store_device_xy01()

void SkSL::RP::Builder::store_device_xy01 ( SlotRange  slots)
inline

Definition at line 348 of file SkSLRasterPipelineBuilder.h.

348 {
349 SkASSERT(slots.count == 4);
350 this->appendInstruction(BuilderOp::store_device_xy01, {slots.index});
351 }

◆ store_dst()

void SkSL::RP::Builder::store_dst ( SlotRange  slots)
inline

Definition at line 343 of file SkSLRasterPipelineBuilder.h.

343 {
344 SkASSERT(slots.count == 4);
345 this->appendInstruction(BuilderOp::store_dst, {slots.index});
346 }

◆ store_immutable_value_i()

void SkSL::RP::Builder::store_immutable_value_i ( Slot  slot,
int32_t  val 
)
inline

Definition at line 405 of file SkSLRasterPipelineBuilder.h.

405 {
406 this->appendInstruction(BuilderOp::store_immutable_value, {slot}, val);
407 }

◆ store_src()

void SkSL::RP::Builder::store_src ( SlotRange  slots)
inline

Definition at line 338 of file SkSLRasterPipelineBuilder.h.

338 {
339 SkASSERT(slots.count == 4);
340 this->appendInstruction(BuilderOp::store_src, {slots.index});
341 }

◆ store_src_rg()

void SkSL::RP::Builder::store_src_rg ( SlotRange  slots)
inline

Definition at line 333 of file SkSLRasterPipelineBuilder.h.

333 {
334 SkASSERT(slots.count == 2);
335 this->appendInstruction(BuilderOp::store_src_rg, {slots.index});
336 }

◆ swizzle()

void SkSL::RP::Builder::swizzle ( int  consumedSlots,
SkSpan< const int8_t >  components 
)

Definition at line 1136 of file SkSLRasterPipelineBuilder.cpp.

1136 {
1137 // Consumes `consumedSlots` elements on the stack, then generates `elementSpan.size()` elements.
1138 SkASSERT(consumedSlots >= 0);
1139
1140 // We only allow up to 16 elements, and they can only reach 0-15 slots, due to nybble packing.
1141 int numElements = components.size();
1142 SkASSERT(numElements <= 16);
1143 SkASSERT(std::all_of(components.begin(), components.end(), [](int8_t e){ return e >= 0; }));
1144 SkASSERT(std::all_of(components.begin(), components.end(), [](int8_t e){ return e <= 0xF; }));
1145
1146 // Make a local copy of the element array.
1147 int8_t elements[16] = {};
1148 std::copy(components.begin(), components.end(), std::begin(elements));
1149
1150 while (numElements > 0) {
1151 // If the first element of the swizzle is zero...
1152 if (elements[0] != 0) {
1153 break;
1154 }
1155 // ...and zero isn't used elsewhere in the swizzle...
1156 if (std::any_of(&elements[1], &elements[numElements], [](int8_t e) { return e == 0; })) {
1157 break;
1158 }
1159 // We can omit the first slot from the swizzle entirely.
1160 // Slide everything forward by one slot, and reduce the element index by one.
1161 for (int index = 1; index < numElements; ++index) {
1162 elements[index - 1] = elements[index] - 1;
1163 }
1164 elements[numElements - 1] = 0;
1165 --consumedSlots;
1166 --numElements;
1167 }
1168
1169 // A completely empty swizzle is a discard.
1170 if (numElements == 0) {
1171 this->discard_stack(consumedSlots);
1172 return;
1173 }
1174
1175 if (consumedSlots <= 4 && numElements <= 4) {
1176 // We can fit everything into a little swizzle.
1177 int op = (int)BuilderOp::swizzle_1 + numElements - 1;
1178 this->appendInstruction((BuilderOp)op, {}, consumedSlots,
1179 pack_nybbles(SkSpan(elements, numElements)));
1180 return;
1181 }
1182
1183 // This is a big swizzle. We use the `shuffle` op to handle these. immA counts the consumed
1184 // slots. immB counts the generated slots. immC and immD hold packed-nybble shuffle values.
1185 this->appendInstruction(BuilderOp::shuffle, {},
1186 consumedSlots, numElements,
1187 pack_nybbles(SkSpan(&elements[0], 8)),
1188 pack_nybbles(SkSpan(&elements[8], 8)));
1189}
static void copy(void *dst, const uint8_t *src, int width, int bpp, int deltaSrc, int offset, const SkPMColor ctable[])
Definition: SkSwizzler.cpp:31
constexpr T * begin() const
Definition: SkSpan_impl.h:90
constexpr T * end() const
Definition: SkSpan_impl.h:91
constexpr size_t size() const
Definition: SkSpan_impl.h:95
static const char * begin(const StringSlice &s)
Definition: editor.cpp:252
static int pack_nybbles(SkSpan< const int8_t > components)
SI Vec< sizeof...(Ix), T > shuffle(const Vec< N, T > &)
Definition: SkVx.h:667

◆ swizzle_copy_stack_to_slots()

void SkSL::RP::Builder::swizzle_copy_stack_to_slots ( SlotRange  dst,
SkSpan< const int8_t >  components,
int  offsetFromStackTop 
)

Definition at line 1098 of file SkSLRasterPipelineBuilder.cpp.

1100 {
1101 // When the execution-mask writes-enabled flag is off, we could squeeze out a little bit of
1102 // extra speed here by implementing and using an unmasked version of this op.
1103
1104 // SlotA: fixed-range start
1105 // immA: number of swizzle components
1106 // immB: swizzle components
1107 // immC: offset from stack top
1108 this->appendInstruction(BuilderOp::swizzle_copy_stack_to_slots, {dst.index},
1109 (int)components.size(),
1110 pack_nybbles(components),
1111 offsetFromStackTop);
1112}

◆ swizzle_copy_stack_to_slots_indirect()

void SkSL::RP::Builder::swizzle_copy_stack_to_slots_indirect ( SlotRange  fixedRange,
int  dynamicStackID,
SlotRange  limitRange,
SkSpan< const int8_t >  components,
int  offsetFromStackTop 
)

Definition at line 1114 of file SkSLRasterPipelineBuilder.cpp.

1118 {
1119 // When the execution-mask writes-enabled flag is off, we could squeeze out a little bit of
1120 // extra speed here by implementing and using an unmasked version of this op.
1121
1122 // SlotA: fixed-range start
1123 // SlotB: limit-range end
1124 // immA: number of swizzle components
1125 // immB: swizzle components
1126 // immC: offset from stack top
1127 // immD: dynamic stack ID
1129 {fixedRange.index, limitRange.index + limitRange.count},
1130 (int)components.size(),
1131 pack_nybbles(components),
1132 offsetFromStackTop,
1133 dynamicStackID);
1134}
@ swizzle_copy_stack_to_slots_indirect

◆ ternary_op()

void SkSL::RP::Builder::ternary_op ( BuilderOp  op,
int32_t  slots 
)

Definition at line 251 of file SkSLRasterPipelineBuilder.cpp.

251 {
252 switch (op) {
255 this->appendInstruction(op, {}, slots);
256 break;
257
258 default:
259 SkDEBUGFAIL("not a ternary op");
260 break;
261 }
262}
#define ALL_N_WAY_TERNARY_OP_CASES
#define ALL_MULTI_SLOT_TERNARY_OP_CASES

◆ trace_enter()

void SkSL::RP::Builder::trace_enter ( int  traceMaskStackID,
int  funcID 
)
inline

Definition at line 719 of file SkSLRasterPipelineBuilder.h.

719 {
720 this->appendInstruction(BuilderOp::trace_enter, {}, traceMaskStackID, funcID);
721 }

◆ trace_exit()

void SkSL::RP::Builder::trace_exit ( int  traceMaskStackID,
int  funcID 
)
inline

Definition at line 724 of file SkSLRasterPipelineBuilder.h.

724 {
725 this->appendInstruction(BuilderOp::trace_exit, {}, traceMaskStackID, funcID);
726 }

◆ trace_line()

void SkSL::RP::Builder::trace_line ( int  traceMaskStackID,
int  line 
)
inline

Definition at line 705 of file SkSLRasterPipelineBuilder.h.

705 {
706 this->appendInstruction(BuilderOp::trace_line, {}, traceMaskStackID, line);
707 }

◆ trace_scope()

void SkSL::RP::Builder::trace_scope ( int  traceMaskStackID,
int  delta 
)
inline

Definition at line 729 of file SkSLRasterPipelineBuilder.h.

729 {
730 this->appendInstruction(BuilderOp::trace_scope, {}, traceMaskStackID, delta);
731 }

◆ trace_var()

void SkSL::RP::Builder::trace_var ( int  traceMaskStackID,
SlotRange  r 
)
inline

Definition at line 710 of file SkSLRasterPipelineBuilder.h.

710 {
711 this->appendInstruction(BuilderOp::trace_var, {r.index}, traceMaskStackID, r.count);
712 }

◆ trace_var_indirect()

void SkSL::RP::Builder::trace_var_indirect ( int  traceMaskStackID,
SlotRange  fixedRange,
int  dynamicStackID,
SlotRange  limitRange 
)

Definition at line 622 of file SkSLRasterPipelineBuilder.cpp.

625 {
626 // SlotA: fixed-range start
627 // SlotB: limit-range end
628 // immA: trace-mask stack ID
629 // immB: number of slots
630 // immC: dynamic stack ID
631 this->appendInstruction(BuilderOp::trace_var_indirect,
632 {fixedRange.index, limitRange.index + limitRange.count},
633 traceMaskStackID,
634 fixedRange.count,
635 dynamicStackID);
636}

◆ transpose()

void SkSL::RP::Builder::transpose ( int  columns,
int  rows 
)

Definition at line 1191 of file SkSLRasterPipelineBuilder.cpp.

1191 {
1192 // Transposes a matrix of size CxR on the stack (into a matrix of size RxC).
1193 int8_t elements[16] = {};
1194 size_t index = 0;
1195 for (int r = 0; r < rows; ++r) {
1196 for (int c = 0; c < columns; ++c) {
1197 elements[index++] = (c * rows) + r;
1198 }
1199 }
1200 this->swizzle(/*consumedSlots=*/columns * rows, SkSpan(elements, index));
1201}

◆ unary_op()

void SkSL::RP::Builder::unary_op ( BuilderOp  op,
int32_t  slots 
)

Definition at line 209 of file SkSLRasterPipelineBuilder.cpp.

209 {
210 switch (op) {
213 this->appendInstruction(op, {}, slots);
214 break;
215
216 default:
217 SkDEBUGFAIL("not a unary op");
218 break;
219 }
220}
#define ALL_MULTI_SLOT_UNARY_OP_CASES
#define ALL_SINGLE_SLOT_UNARY_OP_CASES

◆ zero_slots_unmasked()

void SkSL::RP::Builder::zero_slots_unmasked ( SlotRange  dst)

Definition at line 1046 of file SkSLRasterPipelineBuilder.cpp.

1046 {
1047 if (Instruction* lastInstruction = this->lastInstruction()) {
1048 if (lastInstruction->fOp == BuilderOp::copy_constant && lastInstruction->fImmB == 0) {
1049 if (lastInstruction->fSlotA + lastInstruction->fImmA == dst.index) {
1050 // The previous instruction was zeroing the range immediately before this range.
1051 // Combine the ranges.
1052 lastInstruction->fImmA += dst.count;
1053 return;
1054 }
1055
1056 if (lastInstruction->fSlotA == dst.index + dst.count) {
1057 // The previous instruction was zeroing the range immediately after this range.
1058 // Combine the ranges.
1059 lastInstruction->fSlotA = dst.index;
1060 lastInstruction->fImmA += dst.count;
1061 return;
1062 }
1063 }
1064 }
1065
1066 this->appendInstruction(BuilderOp::copy_constant, {dst.index}, dst.count, 0);
1067}

The documentation for this class was generated from the following files: