91class AutoContinueMask;
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) {
1409 fBuilder.
trace_var(fTraceMask->stackID(), this->getVariableSlots(*var));
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) {
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:
1667 case Statement::Kind::kDo:
1670 case Statement::Kind::kExpression:
1673 case Statement::Kind::kFor:
1676 case Statement::Kind::kIf:
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);
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:
2211 case Expression::Kind::kFieldAccess:
2214 case Expression::Kind::kFunctionCall:
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)
2310 SkASSERT(left.type().isMatrix() || left.type().isVector());
2311 SkASSERT(right.type().isMatrix() || right.type().isVector());
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()) {
2433 SkASSERT(left.type().matches(right.type()));
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;
2481 const Type&
type = vectorizeLeft ? right.type() : left.type();
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,...)
constexpr int SK_FRAGCOORD_BUILTIN
constexpr size_t SkToSizeT(S x)
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 bool supportsConstantValues() const
const Type & type() 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)
std::function< UnitlessTime(int)> Generator
DEF_SWITCHES_START aot vmservice shared library name
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core counts
constexpr bool starts_with(std::string_view str, std::string_view prefix)
constexpr bool contains(std::string_view str, std::string_view needle)
static SkString to_string(int n)
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