91class AutoContinueMask;
97 SlotManager(std::vector<SlotDebugInfo>* i) : fSlotDebugInfo(i) {}
104 bool isFunctionReturnValue);
108 bool isFunctionReturnValue);
114 bool isFunctionReturnValue);
145 std::vector<SlotDebugInfo>* fSlotDebugInfo;
178 int fParentStackID = 0;
185 , fContext(fProgram.fContext->fTypes, *fProgram.fContext->fErrors)
186 , fDebugTrace(debugTrace)
187 , fWriteTraceOps(writeTraceOps)
188 , fProgramSlots(debugTrace ? &debugTrace->fSlotInfo : nullptr)
189 , fUniformSlots(debugTrace ? &debugTrace->fUniformInfo : nullptr)
190 , fImmutableSlots(nullptr) {
205 std::unique_ptr<RP::Program>
finish();
213 SkSpan<std::unique_ptr<Expression>
const> arguments);
223 return !
IsUniform(v) && !fImmutableVariables.contains(&v);
237 SkASSERT(fImmutableVariables.contains(&v));
244 SkASSERT(!fImmutableVariables.contains(&v));
271 return fCurrentStack;
360 fBuilder.
trace_var(fTraceMask->stackID(), r);
366 fBuilder.
trace_var(fTraceMask->stackID(), r);
377 fBuilder.
trace_var(fTraceMask->stackID(), r);
431 int leftColumns,
int leftRows,
432 int rightColumns,
int rightRows);
446 complexity = fReturnComplexityMap.set(fCurrentFunction,
480 bool fWriteTraceOps =
false;
487 std::optional<AutoStack> fTraceMask;
491 int fCurrentBreakTarget = -1;
492 int fCurrentStack = 0;
493 int fNextStackID = 0;
503 int fInsideCompoundStatement = 0;
509 static constexpr auto kAddOps = TypedOps{BuilderOp::add_n_floats,
510 BuilderOp::add_n_ints,
511 BuilderOp::add_n_ints,
513 static constexpr auto kSubtractOps = TypedOps{BuilderOp::sub_n_floats,
514 BuilderOp::sub_n_ints,
515 BuilderOp::sub_n_ints,
517 static constexpr auto kMultiplyOps = TypedOps{BuilderOp::mul_n_floats,
518 BuilderOp::mul_n_ints,
519 BuilderOp::mul_n_ints,
521 static constexpr auto kDivideOps = TypedOps{BuilderOp::div_n_floats,
522 BuilderOp::div_n_ints,
523 BuilderOp::div_n_uints,
525 static constexpr auto kLessThanOps = TypedOps{BuilderOp::cmplt_n_floats,
526 BuilderOp::cmplt_n_ints,
527 BuilderOp::cmplt_n_uints,
529 static constexpr auto kLessThanEqualOps = TypedOps{BuilderOp::cmple_n_floats,
530 BuilderOp::cmple_n_ints,
531 BuilderOp::cmple_n_uints,
533 static constexpr auto kEqualOps = TypedOps{BuilderOp::cmpeq_n_floats,
534 BuilderOp::cmpeq_n_ints,
535 BuilderOp::cmpeq_n_ints,
536 BuilderOp::cmpeq_n_ints};
537 static constexpr auto kNotEqualOps = TypedOps{BuilderOp::cmpne_n_floats,
538 BuilderOp::cmpne_n_ints,
539 BuilderOp::cmpne_n_ints,
540 BuilderOp::cmpne_n_ints};
541 static constexpr auto kModOps = TypedOps{BuilderOp::mod_n_floats,
545 static constexpr auto kMinOps = TypedOps{BuilderOp::min_n_floats,
546 BuilderOp::min_n_ints,
547 BuilderOp::min_n_uints,
548 BuilderOp::min_n_uints};
549 static constexpr auto kMaxOps = TypedOps{BuilderOp::max_n_floats,
550 BuilderOp::max_n_ints,
551 BuilderOp::max_n_uints,
552 BuilderOp::max_n_uints};
553 static constexpr auto kMixOps = TypedOps{BuilderOp::mix_n_floats,
557 static constexpr auto kInverseSqrtOps = TypedOps{BuilderOp::invsqrt_float,
566 , fStackID(g->createStack()) {}
592 range, dynamicStackID, fStackID, offsetFromStackTop);
600 if (fPreviousContinueMask) {
601 fGenerator->fCurrentContinueMask = fPreviousContinueMask;
606 SkASSERT(!fContinueMaskStack.has_value());
608 fContinueMaskStack.emplace(fGenerator);
609 fPreviousContinueMask = fGenerator->fCurrentContinueMask;
610 fGenerator->fCurrentContinueMask =
this;
614 SkASSERT(fContinueMaskStack.has_value());
615 fContinueMaskStack->enter();
619 SkASSERT(fContinueMaskStack.has_value());
620 fContinueMaskStack->exit();
624 if (fContinueMaskStack.has_value()) {
625 fContinueMaskStack->enter();
627 fContinueMaskStack->exit();
632 if (fContinueMaskStack.has_value()) {
633 fContinueMaskStack->enter();
635 fContinueMaskStack->exit();
640 SkASSERT(fContinueMaskStack.has_value());
641 return fContinueMaskStack->stackID();
645 std::optional<AutoStack> fContinueMaskStack;
654 fPreviousLoopTarget = *fLoopTargetPtr;
655 *fLoopTargetPtr = fLabelID;
659 *fLoopTargetPtr = fPreviousLoopTarget;
668 int* fLoopTargetPtr =
nullptr;
669 int fPreviousLoopTarget;
718 , fNumSlots(e.
type().slotCount()) {}
721 if (fGenerator && fDedicatedStack.has_value()) {
723 fDedicatedStack->enter();
725 fDedicatedStack->exit();
745 if (!fDedicatedStack.has_value()) {
748 fDedicatedStack.emplace(fGenerator);
749 fDedicatedStack->enter();
753 fDedicatedStack->exit();
757 fDedicatedStack->pushCloneIndirect(fixedOffset, dynamicOffset->
stackID(), fNumSlots);
759 fDedicatedStack->pushClone(fixedOffset, fNumSlots);
768 SkDEBUGFAIL(
"scratch lvalues cannot be stored into");
775 std::optional<AutoStack> fDedicatedStack;
789 :
gen->getVariableSlots(*fVariable);
802 gen->builder()->push_uniform_indirect(fixedOffset, dynamicOffset->
stackID(),
803 this->fixedSlotRange(
gen));
805 gen->builder()->push_uniform(fixedOffset);
809 gen->builder()->push_slots_indirect(fixedOffset, dynamicOffset->
stackID(),
810 this->fixedSlotRange(
gen));
812 gen->builder()->push_slots(fixedOffset);
829 gen->builder()->copy_stack_to_slots_indirect(fixedOffset, dynamicOffset->
stackID(),
830 this->fixedSlotRange(
gen));
832 gen->builder()->copy_stack_to_slots(fixedOffset);
836 gen->builder()->swizzle_copy_stack_to_slots_indirect(fixedOffset,
838 this->fixedSlotRange(
gen),
842 gen->builder()->swizzle_copy_stack_to_slots(fixedOffset,
swizzle,
swizzle.size());
845 if (
gen->shouldWriteTraceOps()) {
847 gen->builder()->trace_var_indirect(
gen->traceMaskStackID(),
850 this->fixedSlotRange(
gen));
852 gen->builder()->trace_var(
gen->traceMaskStackID(), fixedOffset);
871 return gen->getImmutableSlots(*fVariable);
883 gen->builder()->push_immutable_indirect(fixedOffset, dynamicOffset->
stackID(),
884 this->fixedSlotRange(
gen));
886 gen->builder()->push_immutable(fixedOffset);
898 SkDEBUGFAIL(
"immutable values cannot be stored into");
909 : fParent(
std::move(p))
915 return fParent->isWritable();
919 return fParent->fixedSlotRange(
gen);
923 return fParent->dynamicSlotRange();
935 SkDEBUGFAIL(
"swizzle-of-a-swizzle should have been folded out in front end");
938 return fParent->push(
gen, fixedOffset, dynamicOffset, fComponents);
946 SkDEBUGFAIL(
"swizzle-of-a-swizzle should have been folded out in front end");
949 return fParent->store(
gen, fixedOffset, dynamicOffset, fComponents);
953 std::unique_ptr<LValue> fParent;
961 , fInitialSlot(initialSlot)
962 , fNumSlots(numSlots) {
974 adjusted.
index += fInitialSlot;
975 adjusted.
count = fNumSlots;
1002 int fInitialSlot = 0;
1008 explicit LValueSlice(std::unique_ptr<LValue> p,
int initialSlot,
int numSlots)
1019 : fParent(
std::move(p))
1025 if (fDedicatedStack.has_value()) {
1029 fDedicatedStack->enter();
1031 fDedicatedStack->exit();
1036 return fParent->isWritable();
1042 SkASSERT(!fDedicatedStack.has_value());
1045 fDedicatedStack.emplace(fGenerator);
1047 if (!fParent->swizzle().empty()) {
1048 SkDEBUGFAIL(
"an indexed-swizzle should have been handled by RewriteIndexedSwizzle");
1053 fDedicatedStack->enter();
1060 if (slotCount != 1) {
1067 if (
AutoStack* parentDynamicIndexStack = fParent->dynamicSlotRange()) {
1068 parentDynamicIndexStack->pushClone(1);
1071 fDedicatedStack->exit();
1084 SkASSERT(fDedicatedStack.has_value());
1085 return &*fDedicatedStack;
1092 return fParent->push(
gen, fixedOffset, dynamicOffset,
swizzle);
1099 return fParent->store(
gen, fixedOffset, dynamicOffset,
swizzle);
1104 std::unique_ptr<LValue> fParent;
1105 std::optional<AutoStack> fDedicatedStack;
1113 bool isFunctionReturnValue) {
1115 switch (
type.typeKind()) {
1117 int nslots =
type.columns();
1118 const Type& elemType =
type.componentType();
1119 for (
int slot = 0; slot < nslots; ++slot) {
1121 pos, groupIndex, isFunctionReturnValue);
1126 for (
const Field& field :
type.fields()) {
1128 *field.fType,
pos, groupIndex,
1129 isFunctionReturnValue);
1134 SkASSERTF(0,
"unsupported slot type %d", (
int)
type.typeKind());
1141 int nslots =
type.slotCount();
1143 for (
int slot = 0; slot < nslots; ++slot) {
1145 slotInfo.
name = varName;
1153 fSlotDebugInfo->push_back(std::move(slotInfo));
1163 bool isFunctionReturnValue) {
1172 bool isFunctionReturnValue) {
1173 size_t nslots =
type.slotCount();
1177 if (fSlotDebugInfo) {
1179 SkASSERT(fSlotDebugInfo->size() == (
size_t)fSlotCount);
1182 fSlotDebugInfo->reserve(fSlotCount + nslots);
1186 SkASSERT(fSlotDebugInfo->size() == (
size_t)(fSlotCount + nslots));
1190 fSlotCount += nslots;
1196 const SlotRange* existingEntry = fSlotMap.find(&v);
1197 std::optional<SlotRange> originalRange = existingEntry ? std::optional(*existingEntry)
1199 fSlotMap.set(&v, range);
1200 return originalRange;
1204 fSlotMap.remove(&v);
1209 if (entry !=
nullptr) {
1221 SlotRange* entry = fSlotMap.find(&callSite);
1222 if (entry !=
nullptr) {
1229 fSlotMap.set(&callSite, range);
1237 for (
size_t index = 1; index < components.
size(); ++index) {
1238 if (components[index] != int8_t(components[0] + index)) {
1248 if (fImmutableVariables.contains(variable)) {
1249 return std::make_unique<ImmutableLValue>(variable);
1251 return std::make_unique<VariableLValue>(variable);
1260 return std::make_unique<LValueSlice>(std::move(
base), components[0],
1263 return std::make_unique<SwizzleLValue>(std::move(
base), components);
1272 return std::make_unique<LValueSlice>(std::move(
base), fieldExpr.
initialSlot(),
1285 std::unique_ptr<LValue> lvalue = this->
makeLValue(*rewritten, allowScratch);
1290 lvalue->fScratchExpression = std::move(rewritten);
1299 return std::make_unique<LValueSlice>(std::move(
base), numSlots * indexValue,
1304 auto dynLValue = std::make_unique<DynamicIndexLValue>(std::move(
base), indexExpr);
1305 return dynLValue->evaluateDynamicIndices(
this) ? std::move(dynLValue)
1313 return std::make_unique<ScratchLValue>(e);
1319 return lvalue.
push(
this,
1327 return lvalue.
store(
this,
1340 static constexpr std::string_view
kNoInline =
"noinline ";
1346 for (
size_t index = 0; index < fDebugTrace->
fFuncInfo.size(); ++index) {
1359 if (!fRecycledStacks.
empty()) {
1360 int stackID = fRecycledStacks.
back();
1364 return ++fNextStackID;
1372 if (fCurrentStack != stackID) {
1373 fCurrentStack = stackID;
1381 SkSpan<std::unique_ptr<Expression>
const> arguments) {
1388 fBuilder.
trace_enter(fTraceMask->stackID(), funcIndex);
1393 struct RemappedSlotRange {
1395 std::optional<SlotRange> fSlotRange;
1401 if (
function.declaration().isMain()) {
1408 for (
const Variable* var : parameters) {
1416 lvalues.
resize(arguments.size());
1418 for (
size_t index = 0; index < arguments.size(); ++index) {
1420 const Variable& param = *parameters[index];
1426 if (!lvalues[index]) {
1427 return std::nullopt;
1432 if (!this->
push(*lvalues[index])) {
1433 return std::nullopt;
1442 if (paramCounts.
fRead == 0) {
1446 return std::nullopt;
1458 std::optional<SlotRange> originalRange =
1460 remappedSlotRanges.
push_back({¶m, originalRange});
1467 return std::nullopt;
1474 SlotRange lastFunctionResult = fCurrentFunctionResult;
1480 if (!
function.declaration().isMain()) {
1487 return std::nullopt;
1492 if (!
function.declaration().isMain()) {
1499 SlotRange functionResult = fCurrentFunctionResult;
1500 fCurrentFunctionResult = lastFunctionResult;
1503 if (fDebugTrace && fWriteTraceOps) {
1504 fBuilder.
trace_exit(fTraceMask->stackID(), funcIndex);
1508 for (
int index = 0; index < lvalues.
size(); ++index) {
1509 if (lvalues[index]) {
1511 const Variable& param = *parameters[index];
1516 if (!this->
store(*lvalues[index])) {
1517 return std::nullopt;
1524 for (
const RemappedSlotRange& remapped : remappedSlotRanges) {
1525 if (remapped.fSlotRange.has_value()) {
1532 return functionResult;
1536 if (fDebugTrace && fWriteTraceOps &&
pos.valid() && fInsideCompoundStatement == 0) {
1541 int lineNumber = std::distance(
1542 fLineOffsets.
begin(),
1543 std::upper_bound(fLineOffsets.
begin(), fLineOffsets.
end(),
pos.startOffset()));
1545 fBuilder.
trace_line(fTraceMask->stackID(), lineNumber);
1555 fTraceMask->pushClone(1);
1575 for (
size_t i = 0; i < fProgram.
fSource->length(); ++i) {
1576 if ((*fProgram.
fSource)[i] ==
'\n') {
1592 SkASSERT(!fChildEffectMap.find(var));
1593 int childEffectIndex = fChildEffectMap.count();
1594 fChildEffectMap[var] = childEffectIndex;
1643 case Statement::Kind::kBlock:
1646 case Statement::Kind::kFor:
1658 case Statement::Kind::kBlock:
1661 case Statement::Kind::kBreak:
1664 case Statement::Kind::kContinue:
1667 case Statement::Kind::kDo:
1670 case Statement::Kind::kExpression:
1673 case Statement::Kind::kFor:
1676 case Statement::Kind::kIf:
1679 case Statement::Kind::kNop:
1682 case Statement::Kind::kReturn:
1685 case Statement::Kind::kSwitch:
1688 case Statement::Kind::kVarDeclaration:
1697 if (
b.blockKind() == Block::Kind::kCompoundStatement) {
1699 ++fInsideCompoundStatement;
1705 for (
const std::unique_ptr<Statement>& stmt :
b.children()) {
1711 if (
b.blockKind() == Block::Kind::kCompoundStatement) {
1712 --fInsideCompoundStatement;
1747 autoContinueMask.
enable();
1752 fBuilder.
label(labelID);
1790 SkASSERT(f.unrollInfo()->fCount > 0);
1815 fBuilder.
label(loopBodyID);
1825 }
else if (f.test()) {
1832 if (f.unrollInfo()->fCount > 1) {
1849 fBuilder.
label(loopExitID);
1858 if (f.unrollInfo() && f.unrollInfo()->fCount == 0) {
1879 if (f.initializer()) {
1890 autoContinueMask.
enable();
1901 fBuilder.
jump(loopTestID);
1904 fBuilder.
label(loopBodyID);
1918 }
else if (f.test()) {
1932 fBuilder.
label(loopTestID);
1985 fBuilder.
label(falseLabelID);
1989 fBuilder.
jump(exitLabelID);
1992 fBuilder.
label(falseLabelID);
1998 fBuilder.
label(exitLabelID);
2060 SkASSERT(std::all_of(cases.
begin(), cases.
end(), [](
const std::unique_ptr<Statement>& stmt) {
2061 return stmt->is<SwitchCase>();
2082 bool foundDefaultCase =
false;
2083 for (
const std::unique_ptr<Statement>& stmt : cases) {
2088 foundDefaultCase =
true;
2089 if (stmt.get() != cases.
back().get()) {
2111 fBuilder.
label(skipLabelID);
2139 if (counts.fWrite != 1) {
2148 fImmutableVariables.add(
d.var());
2151 if (preexistingSlots.has_value()) {
2183 case Expression::Kind::kBinary:
2186 case Expression::Kind::kChildCall:
2189 case Expression::Kind::kConstructorArray:
2190 case Expression::Kind::kConstructorArrayCast:
2191 case Expression::Kind::kConstructorCompound:
2192 case Expression::Kind::kConstructorStruct:
2195 case Expression::Kind::kConstructorCompoundCast:
2196 case Expression::Kind::kConstructorScalarCast:
2199 case Expression::Kind::kConstructorDiagonalMatrix:
2202 case Expression::Kind::kConstructorMatrixResize:
2205 case Expression::Kind::kConstructorSplat:
2208 case Expression::Kind::kEmpty:
2211 case Expression::Kind::kFieldAccess:
2214 case Expression::Kind::kFunctionCall:
2217 case Expression::Kind::kIndex:
2220 case Expression::Kind::kLiteral:
2223 case Expression::Kind::kPrefix:
2226 case Expression::Kind::kPostfix:
2229 case Expression::Kind::kSwizzle:
2232 case Expression::Kind::kTernary:
2235 case Expression::Kind::kVariableReference:
2244 switch (
type.componentType().numberKind()) {
2284 for (; elements >= 8; elements -= 4) {
2287 for (; elements >= 6; elements -= 3) {
2290 for (; elements >= 4; elements -= 2) {
2293 for (; elements >= 2; elements -= 1) {
2299 return lvalue ? this->
push(*lvalue)
2314 fBuilder.
pad_stack(rightColumns * leftRows);
2321 fBuilder.
matrix_multiply(leftColumns, leftRows, rightColumns, rightRows);
2324 return lvalue ? this->
store(*lvalue)
2329 switch (op.
kind()) {
2350 if (
type.isStruct()) {
2353 int currentSlot = 0;
2354 for (
size_t index = 0; index < fields.
size(); ++index) {
2355 const Type& fieldType = *fields[index].fType;
2356 const int fieldSlotCount = fieldType.
slotCount();
2362 currentSlot += fieldSlotCount;
2369 if (
type.isArray()) {
2370 const Type& indexedType =
type.componentType();
2373 const int indexedSlotCount = indexedType.
slotCount();
2374 int currentSlot = 0;
2375 for (
int index = 0; index <
type.columns(); ++index) {
2381 currentSlot += indexedSlotCount;
2391 if (!this->
push(*left) || !this->
push(*right)) {
2394 switch (op.
kind()) {
2396 if (!this->
binaryOp(type, kEqualOps)) {
2402 if (!this->
binaryOp(type, kNotEqualOps)) {
2421 switch (op.
kind()) {
2432 if (
left.type().isStruct() ||
left.type().isArray()) {
2434 std::unique_ptr<LValue> lvLeft = this->
makeLValue(left,
true);
2435 std::unique_ptr<LValue> lvRight = this->
makeLValue(right,
true);
2469 bool vectorizeLeft =
false, vectorizeRight =
false;
2470 if (!
left.type().matches(
right.type())) {
2471 if (
left.type().componentType().numberKind() !=
right.type().componentType().numberKind()) {
2474 if (
left.type().isScalar() && (
right.type().isVector() ||
right.type().isMatrix())) {
2475 vectorizeLeft =
true;
2476 }
else if ((
left.type().isVector() ||
left.type().isMatrix()) &&
right.type().isScalar()) {
2477 vectorizeRight =
true;
2484 std::unique_ptr<LValue> lvalue;
2495 this->
store(*lvalue);
2505 if (
left.type().isMatrix() &&
right.type().isMatrix()) {
2507 left.type().columns(),
left.type().rows(),
2508 right.type().columns(),
right.type().rows());
2512 if (
left.type().isVector() &&
right.type().isMatrix()) {
2514 left.type().columns(), 1,
2515 right.type().columns(),
right.type().rows());
2519 if (
left.type().isMatrix() &&
right.type().isVector()) {
2521 left.type().columns(),
left.type().rows(),
2522 1,
right.type().columns());
2526 if (!vectorizeLeft && !vectorizeRight && !
type.matches(
right.type())) {
2532 switch (op.
kind()) {
2564 if (vectorizeLeft) {
2570 if (vectorizeRight) {
2574 switch (op.
kind()) {
2576 if (!this->
binaryOp(type, kAddOps)) {
2582 if (!this->
binaryOp(type, kSubtractOps)) {
2588 if (!this->
binaryOp(type, kMultiplyOps)) {
2594 if (!this->
binaryOp(type, kDivideOps)) {
2601 if (!this->
binaryOp(type, kLessThanOps)) {
2609 if (!this->
binaryOp(type, kLessThanEqualOps)) {
2616 if (!this->
binaryOp(type, kEqualOps)) {
2623 if (!this->
binaryOp(type, kNotEqualOps)) {
2633 fBuilder.
binary_op(BuilderOp::bitwise_and_n_ints,
type.slotCount());
2639 fBuilder.
binary_op(BuilderOp::bitwise_or_n_ints,
type.slotCount());
2645 fBuilder.
binary_op(BuilderOp::bitwise_xor_n_ints,
type.slotCount());
2653 return lvalue ? this->
store(*lvalue)
2661 if (!v.has_value()) {
2662 return std::nullopt;
2669 return sk_bit_cast<ImmutableBits>((
float)
value);
2672 return sk_bit_cast<ImmutableBits>((int32_t)
value);
2675 return sk_bit_cast<ImmutableBits>((uint32_t)
value);
2678 return value ? ~0 : 0;
2681 return std::nullopt;
2692 for (
size_t index = 0; index < numSlots; ++index) {
2694 if (!bits.has_value()) {
2704 for (
int index = 0; index < slots.
count; ++index) {
2711 fImmutableSlotMap[bits].add(slot);
2722 for (
const ImmutableBits& immutableValue : immutableValues) {
2724 if (!slotsForValue) {
2725 return std::nullopt;
2732 int leastSlotIndex = 0, leastSlotCount = INT_MAX;
2733 for (
int index = 0; index < slotArray.
size(); ++index) {
2734 int currentCount = slotArray[index]->count();
2735 if (currentCount < leastSlotCount) {
2736 leastSlotIndex = index;
2737 leastSlotCount = currentCount;
2742 for (
int slot : *slotArray[leastSlotIndex]) {
2743 int firstSlot = slot - leastSlotIndex;
2745 for (
int index = 0; index < slotArray.
size(); ++index) {
2746 if (!slotArray[index]->
contains(firstSlot + index)) {
2758 return std::nullopt;
2767 if (preexistingData.has_value()) {
2781 if (c.
type().
slotCount() > 1 && this->pushImmutableData(c)) {
2784 for (
const std::unique_ptr<Expression> &arg : c.
argumentSpan()) {
2793 int* childIdx = fChildEffectMap.find(&c.
child());
2871 if (innerKind == outerKind) {
2876 switch (innerKind) {
2974 std::unique_ptr<LValue> lvalue = this->
makeLValue(f,
true);
2975 return lvalue && this->
push(*lvalue);
2995 if (!r.has_value()) {
3005 fCurrentFunction = lastFunction;
3008 fBuilder.
label(skipLabelID);
3013 std::unique_ptr<LValue> lvalue = this->
makeLValue(i,
true);
3014 return lvalue && this->
push(*lvalue);
3019 switch (
args.size()) {
3037 if (slotCount == 1) {
3044 fBuilder.
unary_op(BuilderOp::sqrt_float, 1);
3051 fBuilder.
binary_op(BuilderOp::bitwise_and_n_ints, slots);
3082 switch (intrinsic) {
3083 case IntrinsicKind::k_abs_IntrinsicKind:
3094 case IntrinsicKind::k_any_IntrinsicKind:
3101 case IntrinsicKind::k_all_IntrinsicKind:
3108 case IntrinsicKind::k_acos_IntrinsicKind:
3111 case IntrinsicKind::k_asin_IntrinsicKind:
3114 case IntrinsicKind::k_atan_IntrinsicKind:
3117 case IntrinsicKind::k_ceil_IntrinsicKind:
3120 case IntrinsicKind::k_cos_IntrinsicKind:
3123 case IntrinsicKind::k_degrees_IntrinsicKind: {
3127 case IntrinsicKind::k_floatBitsToInt_IntrinsicKind:
3128 case IntrinsicKind::k_floatBitsToUint_IntrinsicKind:
3129 case IntrinsicKind::k_intBitsToFloat_IntrinsicKind:
3130 case IntrinsicKind::k_uintBitsToFloat_IntrinsicKind:
3133 case IntrinsicKind::k_exp_IntrinsicKind:
3136 case IntrinsicKind::k_exp2_IntrinsicKind:
3139 case IntrinsicKind::k_floor_IntrinsicKind:
3142 case IntrinsicKind::k_fract_IntrinsicKind:
3151 case IntrinsicKind::k_inverse_IntrinsicKind:
3160 case IntrinsicKind::k_inversesqrt_IntrinsicKind:
3163 case IntrinsicKind::k_length_IntrinsicKind:
3167 case IntrinsicKind::k_log_IntrinsicKind:
3174 case IntrinsicKind::k_log2_IntrinsicKind:
3181 case IntrinsicKind::k_normalize_IntrinsicKind: {
3187 if (slotCount > 1) {
3188#if defined(SK_USE_RSQRT_IN_RP_NORMALIZE)
3196 fBuilder.
unary_op(BuilderOp::invsqrt_float, 1);
3210 fBuilder.
unary_op(BuilderOp::sqrt_float, 1);
3223 case IntrinsicKind::k_not_IntrinsicKind:
3226 case IntrinsicKind::k_radians_IntrinsicKind: {
3230 case IntrinsicKind::k_saturate_IntrinsicKind: {
3234 return this->
pushIntrinsic(k_clamp_IntrinsicKind, arg0, zeroLiteral, oneLiteral);
3236 case IntrinsicKind::k_sign_IntrinsicKind: {
3267 case IntrinsicKind::k_sin_IntrinsicKind:
3270 case IntrinsicKind::k_sqrt_IntrinsicKind:
3273 case IntrinsicKind::k_tan_IntrinsicKind:
3276 case IntrinsicKind::k_transpose_IntrinsicKind:
3284 case IntrinsicKind::k_trunc_IntrinsicKind:
3293 case IntrinsicKind::k_fromLinearSrgb_IntrinsicKind:
3294 case IntrinsicKind::k_toLinearSrgb_IntrinsicKind:
3301 if (intrinsic == IntrinsicKind::k_fromLinearSrgb_IntrinsicKind) {
3332 switch (intrinsic) {
3333 case IntrinsicKind::k_atan_IntrinsicKind:
3334 return this->
pushIntrinsic(BuilderOp::atan2_n_floats, arg0, arg1);
3336 case IntrinsicKind::k_cross_IntrinsicKind: {
3345 subexpressionStack.
enter();
3349 subexpressionStack.
exit();
3352 fBuilder.
swizzle(3, {1, 2, 0});
3353 subexpressionStack.
enter();
3354 fBuilder.
swizzle(3, {2, 0, 1});
3355 subexpressionStack.
exit();
3360 subexpressionStack.
enter();
3364 subexpressionStack.
exit();
3367 fBuilder.
swizzle(3, {2, 0, 1});
3368 fBuilder.
binary_op(BuilderOp::mul_n_floats, 3);
3370 subexpressionStack.
enter();
3371 fBuilder.
swizzle(3, {1, 2, 0});
3372 fBuilder.
binary_op(BuilderOp::mul_n_floats, 3);
3373 subexpressionStack.
exit();
3378 fBuilder.
binary_op(BuilderOp::sub_n_floats, 3);
3381 subexpressionStack.
enter();
3383 subexpressionStack.
exit();
3386 case IntrinsicKind::k_distance_IntrinsicKind:
3392 case IntrinsicKind::k_dot_IntrinsicKind:
3400 case IntrinsicKind::k_equal_IntrinsicKind:
3404 case IntrinsicKind::k_notEqual_IntrinsicKind:
3408 case IntrinsicKind::k_lessThan_IntrinsicKind:
3412 case IntrinsicKind::k_greaterThan_IntrinsicKind:
3416 case IntrinsicKind::k_lessThanEqual_IntrinsicKind:
3420 case IntrinsicKind::k_greaterThanEqual_IntrinsicKind:
3424 case IntrinsicKind::k_min_IntrinsicKind:
3428 case IntrinsicKind::k_matrixCompMult_IntrinsicKind:
3432 case IntrinsicKind::k_max_IntrinsicKind:
3436 case IntrinsicKind::k_mod_IntrinsicKind:
3440 case IntrinsicKind::k_pow_IntrinsicKind:
3442 return this->
pushIntrinsic(BuilderOp::pow_n_floats, arg0, arg1);
3444 case IntrinsicKind::k_reflect_IntrinsicKind: {
3462 fBuilder.
binary_op(BuilderOp::mul_n_floats, 1);
3465 fBuilder.
binary_op(BuilderOp::mul_n_floats, slotCount);
3467 fBuilder.
binary_op(BuilderOp::sub_n_floats, slotCount);
3470 case IntrinsicKind::k_step_IntrinsicKind: {
3498 switch (intrinsic) {
3499 case IntrinsicKind::k_clamp_IntrinsicKind:
3517 case IntrinsicKind::k_faceforward_IntrinsicKind: {
3535 fBuilder.
binary_op(BuilderOp::cmple_n_floats, 1);
3539 fBuilder.
binary_op(BuilderOp::bitwise_and_n_ints, 1);
3543 fBuilder.
binary_op(BuilderOp::bitwise_xor_n_ints, slotCount);
3546 case IntrinsicKind::k_mix_IntrinsicKind:
3574 case IntrinsicKind::k_refract_IntrinsicKind: {
3597 case IntrinsicKind::k_smoothstep_IntrinsicKind:
3603 !this->pushVectorizedExpression(arg1, arg2.
type()) ||
3604 !this->pushExpression(arg2)) {
3647 if (!lvalue || !this->
push(*lvalue)) {
3660 switch (p.getOperator().kind()) {
3678 if (!this->
store(*lvalue)) {
3692 switch (op.
kind()) {
3736 SkASSERT(!
s.components().empty() &&
s.components().size() <= 4);
3746 SlotRange{s.components()[0], s.components().size()});
3753 if (isSimpleSubset &&
s.components()[0] == 0) {
3754 int discardedElements =
s.base()->type().slotCount() -
s.components().size();
3760 fBuilder.
swizzle(
s.base()->type().slotCount(),
s.components());
3792 fBuilder.
jump(exitLabelID);
3800 fBuilder.
label(falseLabelID);
3806 fBuilder.
label(exitLabelID);
3833 if (!ifFalseHasSideEffects && !ifTrueHasSideEffects && ifTrueIsTrivial) {
3862 if (!ifFalseHasSideEffects) {
3875 if (!ifTrueIsTrivial) {
3886 fBuilder.
label(cleanupLabelID);
3930 if (fImmutableVariables.contains(var.
variable())) {
3947 }
else if (fImmutableVariables.contains(&var)) {
3950 if (subset.
count == 1) {
3953 if (bits.has_value()) {
3982 if (fWriteTraceOps) {
3987 fTraceMask.emplace(
this);
3988 fTraceMask->enter();
3993 fBuilder.
binary_op(BuilderOp::cmpeq_n_floats, 2);
3994 fBuilder.
binary_op(BuilderOp::bitwise_and_n_ints, 1);
4008 if (param == mainCoordsParam) {
4013 }
else if (param == mainInputColorParam) {
4018 }
else if (param == mainDestColorParam) {
4039 if (!mainResult.has_value()) {
4052 if (fTraceMask.has_value()) {
4053 fTraceMask->enter();
4073 bool writeTraceOps) {
4074 RP::Generator generator(program, debugTrace, writeTraceOps);
4078 return generator.
finish();
#define SkDEBUGFAIL(message)
#define SkDEBUGFAILF(fmt,...)
#define SkASSERTF(cond, fmt,...)
static bool contains(const SkRect &r, SkPoint p)
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
constexpr int SK_FRAGCOORD_BUILTIN
constexpr size_t SkToSizeT(S x)
Type::kYUV Type::kRGBA() int(0.7 *637)
virtual SkSpan< std::unique_ptr< Expression > > argumentSpan()=0
std::unique_ptr< Expression > & left()
const std::unique_ptr< Type > fFloat2
const std::unique_ptr< Type > fHalf4
const std::unique_ptr< Type > fFloat4
const std::unique_ptr< Type > fHalf3
ExpressionArray & arguments()
const Variable & child() const
static bool GetConstantValue(const Expression &value, double *out)
static bool GetConstantInt(const Expression &value, SKSL_INT *out)
static const Expression * GetConstantValueOrNull(const Expression &value)
static const Expression * GetConstantValueForVariable(const Expression &value)
const BuiltinTypes & fTypes
std::vector< FunctionDebugInfo > fFuncInfo
void setSource(const std::string &source)
std::unique_ptr< Expression > & test()
std::unique_ptr< Statement > & statement()
const std::unique_ptr< Expression > & expression() const
virtual const Type & type() const
virtual bool supportsConstantValues() const
virtual std::optional< double > getConstantValue(int n) const
AnyConstructor & asAnyConstructor()
std::unique_ptr< Expression > & base()
size_t initialSlot() const
std::unique_ptr< Statement > & statement()
std::unique_ptr< Expression > & next()
std::unique_ptr< Expression > & test()
std::unique_ptr< Statement > & initializer()
ExpressionArray & arguments()
const FunctionDeclaration & function() const
std::string description() const override
const FunctionDefinition * definition() const
IntrinsicKind intrinsicKind() const
std::unique_ptr< Statement > & body()
const FunctionDeclaration & declaration() const
VarDeclaration & varDeclaration()
std::unique_ptr< Expression > & test()
std::unique_ptr< Statement > & ifTrue()
std::unique_ptr< Statement > & ifFalse()
std::unique_ptr< Expression > & base()
std::unique_ptr< Expression > & index()
SKSL_INT boolValue() const
SKSL_INT intValue() const
Operator removeAssignment() const
bool isAssignment() const
Operator getOperator() const
std::unique_ptr< Expression > & operand()
Operator getOperator() const
AutoContinueMask(Generator *gen)
AutoLoopTarget(Generator *gen, int *targetPtr)
void pushClone(int slots)
void pushCloneIndirect(SlotRange range, int dynamicStackID, int offsetFromStackTop)
void dot_floats(int32_t slots)
void push_constant_u(uint32_t val, int count=1)
void push_duplicates(int count)
void invoke_from_linear_srgb()
void store_dst(SlotRange slots)
void push_slots(SlotRange src)
void pad_stack(int32_t count)
void binary_op(BuilderOp op, int32_t slots)
void branch_if_no_lanes_active(int labelID)
void merge_condition_mask()
void push_clone_indirect_from_stack(SlotRange fixedOffset, int dynamicStackID, int otherStackID, int offsetFromStackTop)
void store_immutable_value_i(Slot slot, int32_t val)
void push_clone(int numSlots, int offsetFromStackTop=0)
void zero_slots_unmasked(SlotRange dst)
void swizzle(int consumedSlots, SkSpan< const int8_t > components)
void matrix_resize(int origColumns, int origRows, int newColumns, int newRows)
void branch_if_no_active_lanes_on_stack_top_equal(int value, int labelID)
void inverse_matrix(int32_t n)
void push_uniform(SlotRange src)
void pop_slots(SlotRange dst)
void invoke_color_filter(int childIdx)
void transpose(int columns, int rows)
void mask_off_loop_mask()
void mask_off_return_mask()
void discard_stack(int32_t count, int stackID)
void pop_and_reenable_loop_mask()
void enableExecutionMaskWrites()
void trace_line(int traceMaskStackID, int line)
void trace_enter(int traceMaskStackID, int funcID)
void load_src(SlotRange slots)
void invoke_shader(int childIdx)
void invoke_blender(int childIdx)
void trace_var(int traceMaskStackID, SlotRange r)
void disableExecutionMaskWrites()
void continue_op(int continueMaskStackID)
void store_src(SlotRange slots)
std::unique_ptr< Program > finish(int numValueSlots, int numUniformSlots, int numImmutableSlots, DebugTracePriv *debugTrace=nullptr)
void invoke_to_linear_srgb()
void ternary_op(BuilderOp op, int32_t slots)
void push_constant_f(float val)
void diagonal_matrix(int columns, int rows)
void trace_scope(int traceMaskStackID, int delta)
void store_src_rg(SlotRange slots)
void merge_inv_condition_mask()
void push_clone_from_stack(SlotRange range, int otherStackID, int offsetFromStackTop)
void unary_op(BuilderOp op, int32_t slots)
void push_immutable(SlotRange src)
void push_constant_i(int32_t val, int count=1)
void push_condition_mask()
bool executionMaskWritesAreEnabled()
void matrix_multiply(int leftColumns, int leftRows, int rightColumns, int rightRows)
void branch_if_all_lanes_active(int labelID)
void store_device_xy01(SlotRange slots)
void trace_exit(int traceMaskStackID, int funcID)
void set_current_stack(int stackID)
void pop_slots_unmasked(SlotRange dst)
void branch_if_any_lanes_active(int labelID)
void push_zeros(int count)
void pop_condition_mask()
SlotRange fixedSlotRange(Generator *gen) override
~DynamicIndexLValue() override
bool store(Generator *gen, SlotRange fixedOffset, AutoStack *dynamicOffset, SkSpan< const int8_t > swizzle) override
bool push(Generator *gen, SlotRange fixedOffset, AutoStack *dynamicOffset, SkSpan< const int8_t > swizzle) override
DynamicIndexLValue(std::unique_ptr< LValue > p, const IndexExpression &i)
AutoStack * dynamicSlotRange() override
bool isWritable() const override
bool evaluateDynamicIndices(Generator *gen)
bool pushIntrinsic(const FunctionCall &c)
bool shouldWriteTraceOps()
bool pushLengthIntrinsic(int slotCount)
bool getImmutableValueForExpression(const Expression &expr, TArray< ImmutableBits > *immutableValues)
BuilderOp getTypedOp(const SkSL::Type &type, const TypedOps &ops) const
bool pushTernaryExpression(const TernaryExpression &t)
bool pushConstructorCast(const AnyConstructor &c)
bool pushConstructorDiagonalMatrix(const ConstructorDiagonalMatrix &c)
std::unique_ptr< LValue > makeLValue(const Expression &e, bool allowScratch=false)
bool needsReturnMask(const FunctionDefinition *func)
bool store(LValue &lvalue)
bool ternaryOp(const SkSL::Type &type, const TypedOps &ops)
void popToSlotRangeUnmasked(SlotRange r)
void foldComparisonOp(Operator op, int elements)
void foldWithMultiOp(BuilderOp op, int elements)
void discardTraceScopeMask()
int getFunctionDebugInfo(const FunctionDeclaration &decl)
bool writeReturnStatement(const ReturnStatement &r)
bool pushAbsFloatIntrinsic(int slots)
static BuilderOp GetTypedOp(const SkSL::Type &type, const TypedOps &ops)
std::optional< SlotRange > findPreexistingImmutableData(const TArray< ImmutableBits > &immutableValues)
bool writeProgram(const FunctionDefinition &function)
bool writeMasklessForStatement(const ForStatement &f)
SlotRange getFunctionSlots(const IRNode &callSite, const FunctionDeclaration &f)
static bool IsUniform(const Variable &var)
SlotRange getUniformSlots(const Variable &v)
SlotRange getVariableSlots(const Variable &v)
bool push(LValue &lvalue)
void calculateLineOffsets()
bool pushFunctionCall(const FunctionCall &c)
bool pushImmutableData(const Expression &e)
bool hasVariableSlots(const Variable &v)
bool binaryOp(const SkSL::Type &type, const TypedOps &ops)
bool pushVectorizedExpression(const Expression &expr, const Type &vectorType)
bool writeDoStatement(const DoStatement &d)
bool writeImmutableVarDeclaration(const VarDeclaration &d)
bool writeExpressionStatement(const ExpressionStatement &e)
void zeroSlotRangeUnmasked(SlotRange r)
void emitTraceScope(int delta)
bool pushConstructorSplat(const ConstructorSplat &c)
bool writeStatement(const Statement &s)
SlotRange getImmutableSlots(const Variable &v)
void emitTraceLine(Position pos)
bool needsFunctionResultSlots(const FunctionDefinition *func)
Analysis::ReturnComplexity returnComplexity(const FunctionDefinition *func)
bool pushVariableReference(const VariableReference &v)
bool pushLiteral(const Literal &l)
bool pushConstructorCompound(const AnyConstructor &c)
bool pushFieldAccess(const FieldAccess &f)
bool pushLValueOrExpression(LValue *lvalue, const Expression &expr)
bool pushMatrixMultiply(LValue *lvalue, const Expression &left, const Expression &right, int leftColumns, int leftRows, int rightColumns, int rightRows)
bool pushSwizzle(const Swizzle &s)
std::optional< ImmutableBits > getImmutableBitsForSlot(const Expression &expr, size_t slot)
Generator(const SkSL::Program &program, DebugTracePriv *debugTrace, bool writeTraceOps)
static bool IsInoutParameter(const Variable &var)
bool pushStructuredComparison(LValue *left, Operator op, LValue *right, const Type &type)
void popToSlotRange(SlotRange r)
bool pushBinaryExpression(const BinaryExpression &e)
bool pushPostfixExpression(const PostfixExpression &p, bool usesResult)
std::optional< SlotRange > writeFunction(const IRNode &callSite, const FunctionDefinition &function, SkSpan< std::unique_ptr< Expression > const > arguments)
void setCurrentStack(int stackID)
void recycleStack(int stackID)
bool pushExpression(const Expression &e, bool usesResult=true)
bool writeBreakStatement(const BreakStatement &b)
bool pushVariableReferencePartial(const VariableReference &v, SlotRange subset)
bool writeDynamicallyUniformIfStatement(const IfStatement &i)
bool writeIfStatement(const IfStatement &i)
void storeImmutableValueToSlots(const TArray< ImmutableBits > &immutableValues, SlotRange slots)
void pushTraceScopeMask()
bool writeVarDeclaration(const VarDeclaration &v)
bool pushIndexExpression(const IndexExpression &i)
bool writeContinueStatement(const ContinueStatement &b)
bool pushPrefixExpression(const PrefixExpression &p)
std::unique_ptr< RP::Program > finish()
bool pushChildCall(const ChildCall &c)
static bool IsOutParameter(const Variable &var)
bool writeForStatement(const ForStatement &f)
bool unaryOp(const SkSL::Type &type, const TypedOps &ops)
void discardExpression(int slots)
bool pushConstructorMatrixResize(const ConstructorMatrixResize &c)
bool pushDynamicallyUniformTernaryExpression(const Expression &test, const Expression &ifTrue, const Expression &ifFalse)
bool writeSwitchStatement(const SwitchStatement &s)
bool writeBlock(const Block &b)
AutoStack * dynamicSlotRange() override
bool store(Generator *gen, SlotRange fixedOffset, AutoStack *dynamicOffset, SkSpan< const int8_t > swizzle) override
ImmutableLValue(const Variable *v)
bool isWritable() const override
SlotRange fixedSlotRange(Generator *gen) override
bool push(Generator *gen, SlotRange fixedOffset, AutoStack *dynamicOffset, SkSpan< const int8_t > swizzle) override
LValueSlice(std::unique_ptr< LValue > p, int initialSlot, int numSlots)
virtual bool push(Generator *gen, SlotRange fixedOffset, AutoStack *dynamicOffset, SkSpan< const int8_t > swizzle)=0
virtual ~LValue()=default
virtual bool store(Generator *gen, SlotRange fixedOffset, AutoStack *dynamicOffset, SkSpan< const int8_t > swizzle)=0
std::unique_ptr< Expression > fScratchExpression
virtual SkSpan< const int8_t > swizzle()
virtual SlotRange fixedSlotRange(Generator *gen)=0
virtual bool isWritable() const =0
virtual AutoStack * dynamicSlotRange()=0
ScratchLValue(const Expression &e)
~ScratchLValue() override
bool push(Generator *gen, SlotRange fixedOffset, AutoStack *dynamicOffset, SkSpan< const int8_t > swizzle) override
AutoStack * dynamicSlotRange() override
bool store(Generator *, SlotRange, AutoStack *, SkSpan< const int8_t >) override
bool isWritable() const override
SlotRange fixedSlotRange(Generator *gen) override
SlotRange createSlots(std::string name, const Type &type, Position pos, bool isFunctionReturnValue)
void addSlotDebugInfo(const std::string &varName, const Type &type, Position pos, bool isFunctionReturnValue)
void addSlotDebugInfoForGroup(const std::string &varName, const Type &type, Position pos, int *groupIndex, bool isFunctionReturnValue)
SlotManager(std::vector< SlotDebugInfo > *i)
SlotRange getVariableSlots(const Variable &v)
SlotRange getFunctionSlots(const IRNode &callSite, const FunctionDeclaration &f)
std::optional< SlotRange > mapVariableToSlots(const Variable &v, SlotRange range)
void unmapVariableSlots(const Variable &v)
SlotRange fixedSlotRange(Generator *gen) override
bool store(Generator *gen, SlotRange fixedOffset, AutoStack *dynamicOffset, SkSpan< const int8_t > swizzle) override
bool isWritable() const override
SwizzleLValue(std::unique_ptr< LValue > p, const ComponentArray &c)
AutoStack * dynamicSlotRange() override
bool push(Generator *gen, SlotRange fixedOffset, AutoStack *dynamicOffset, SkSpan< const int8_t > swizzle) override
SkSpan< const int8_t > swizzle() override
bool push(Generator *gen, SlotRange fixedOffset, AutoStack *dynamicOffset, SkSpan< const int8_t > swizzle) override
UnownedLValueSlice(LValue *p, int initialSlot, int numSlots)
SlotRange fixedSlotRange(Generator *gen) override
AutoStack * dynamicSlotRange() override
bool isWritable() const override
bool store(Generator *gen, SlotRange fixedOffset, AutoStack *dynamicOffset, SkSpan< const int8_t > swizzle) override
AutoStack * dynamicSlotRange() override
SlotRange fixedSlotRange(Generator *gen) override
bool isWritable() const override
VariableLValue(const Variable *v)
bool store(Generator *gen, SlotRange fixedOffset, AutoStack *dynamicOffset, SkSpan< const int8_t > swizzle) override
bool push(Generator *gen, SlotRange fixedOffset, AutoStack *dynamicOffset, SkSpan< const int8_t > swizzle) override
std::unique_ptr< Expression > & expression()
std::unique_ptr< Expression > & argument()
std::unique_ptr< Statement > & statement()
std::unique_ptr< Expression > & value()
std::unique_ptr< Expression > & base()
const ComponentArray & components() const
std::string_view name() const
const Type & type() const
std::unique_ptr< Expression > & ifTrue()
std::unique_ptr< Expression > & test()
std::unique_ptr< Expression > & ifFalse()
virtual const Type & slotType(size_t) const
virtual bool isVector() const
bool isEffectChild() const
virtual const Type & componentType() const
bool matches(const Type &other) const
virtual bool isMatrix() const
virtual int columns() const
virtual size_t slotCount() const
virtual bool isScalar() const
virtual NumberKind numberKind() const
std::string description() const override
TypeKind typeKind() const
std::unique_ptr< Expression > & value()
const Variable * variable() const
const Expression * initialValue() const
ModifierFlags modifierFlags() const
virtual const Layout & layout() const
constexpr size_t size() const
void resize(size_t count)
void reserve_exact(int n)
V * find(const K &key) const
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
Dart_NativeFunction function
ReturnComplexity GetReturnComplexity(const FunctionDefinition &funcDef)
LoopControlFlowInfo GetLoopControlFlowInfo(const Statement &stmt)
bool IsTrivialExpression(const Expression &expr)
bool HasSideEffects(const Expression &expr)
bool IsDynamicallyUniformExpression(const Expression &expr)
static bool is_sliceable_swizzle(SkSpan< const int8_t > components)
static bool unsupported()
std::unique_ptr< RP::Program > MakeRasterPipelineProgram(const SkSL::Program &program, const FunctionDefinition &function, DebugTracePriv *debugTrace, bool writeTraceOps)
constexpr bool starts_with(std::string_view str, std::string_view prefix)
ElementsCollection elements() const
std::shared_ptr< Context > fContext
std::unique_ptr< ProgramUsage > fUsage
std::unique_ptr< std::string > fSource
std::unique_ptr< ProgramConfig > fConfig
SkSL::Type::NumberKind numberKind