97#ifdef SK_ENABLE_SPIRV_VALIDATION
98#include "spirv-tools/libspirv.hpp"
103#define kLast_Capability SpvCapabilityMultiViewport
154 enum IntrinsicOpcodeKind {
155 kGLSL_STD_450_IntrinsicOpcodeKind,
156 kSPIRV_IntrinsicOpcodeKind,
157 kSpecial_IntrinsicOpcodeKind,
158 kInvalid_IntrinsicOpcodeKind,
161 enum SpecialIntrinsic {
162 kAtan_SpecialIntrinsic,
163 kClamp_SpecialIntrinsic,
164 kMatrixCompMult_SpecialIntrinsic,
165 kMax_SpecialIntrinsic,
166 kMin_SpecialIntrinsic,
167 kMix_SpecialIntrinsic,
168 kMod_SpecialIntrinsic,
169 kDFdy_SpecialIntrinsic,
170 kSaturate_SpecialIntrinsic,
171 kSampledImage_SpecialIntrinsic,
172 kSmoothStep_SpecialIntrinsic,
173 kStep_SpecialIntrinsic,
174 kSubpassLoad_SpecialIntrinsic,
175 kTexture_SpecialIntrinsic,
176 kTextureGrad_SpecialIntrinsic,
177 kTextureLod_SpecialIntrinsic,
178 kTextureRead_SpecialIntrinsic,
179 kTextureWrite_SpecialIntrinsic,
180 kTextureWidth_SpecialIntrinsic,
181 kTextureHeight_SpecialIntrinsic,
182 kAtomicAdd_SpecialIntrinsic,
183 kAtomicLoad_SpecialIntrinsic,
184 kAtomicStore_SpecialIntrinsic,
185 kStorageBarrier_SpecialIntrinsic,
186 kWorkgroupBarrier_SpecialIntrinsic,
187 kLoadFloatBuffer_SpecialIntrinsic,
190 enum class Precision {
198 std::unique_ptr<SPIRVCodeGenerator::LValue> lvalue;
207 SpvId nextId(Precision precision);
211 SpvId getType(
const Type&
type,
const Layout& typeLayout,
const MemoryLayout& memoryLayout);
215 SpvId getFunctionParameterType(
const Type& parameterType,
const Layout& parameterLayout);
221 const MemoryLayout& memoryLayout,
230 SpvId writeStruct(
const Type&
type,
const MemoryLayout& memoryLayout);
232 void writeProgramElement(
const ProgramElement& pe, OutputStream&
out);
234 SpvId writeInterfaceBlock(
const InterfaceBlock& intf,
bool appendRTFlip =
true);
236 SpvId writeFunctionStart(
const FunctionDeclaration&
f, OutputStream&
out);
238 SpvId writeFunctionDeclaration(
const FunctionDeclaration&
f, OutputStream&
out);
240 SpvId writeFunction(
const FunctionDefinition&
f, OutputStream&
out);
242 bool writeGlobalVarDeclaration(
ProgramKind kind,
const VarDeclaration& v);
246 void writeVarDeclaration(
const VarDeclaration& var, OutputStream&
out);
248 SpvId writeVariableReference(
const VariableReference& ref, OutputStream&
out);
250 int findUniformFieldIndex(
const Variable& var)
const;
252 std::unique_ptr<LValue> getLValue(
const Expression&
value, OutputStream&
out);
254 SpvId writeExpression(
const Expression& expr, OutputStream&
out);
256 SpvId writeIntrinsicCall(
const FunctionCall& c, OutputStream&
out);
258 SpvId writeFunctionCallArgument(
const FunctionCall&
call,
260 std::vector<TempVar>* tempVars,
262 SpvId* outSynthesizedSamplerId =
nullptr);
264 void copyBackTempVars(
const std::vector<TempVar>& tempVars, OutputStream&
out);
266 SpvId writeFunctionCall(
const FunctionCall& c, OutputStream&
out);
279 SpvId vectorize(
const Expression& expr,
int vectorSize, OutputStream&
out);
295 SpvId writeSpecialIntrinsic(
const FunctionCall& c, SpecialIntrinsic kind, OutputStream&
out);
296 SpvId writeAtomicIntrinsic(
const FunctionCall& c,
297 SpecialIntrinsic kind,
304 SpvId castScalarToSignedInt(
SpvId inputId,
const Type& inputType,
const Type& outputType,
307 SpvId castScalarToUnsignedInt(
SpvId inputId,
const Type& inputType,
const Type& outputType,
310 SpvId castScalarToBoolean(
SpvId inputId,
const Type& inputType,
const Type& outputType,
313 SpvId castScalarToType(
SpvId inputExprId,
const Type& inputType,
const Type& outputType,
323 void addColumnEntry(
const Type& columnType,
326 int rows,
SpvId entry, OutputStream&
out);
328 SpvId writeConstructorCompound(
const ConstructorCompound& c, OutputStream&
out);
330 SpvId writeMatrixConstructor(
const ConstructorCompound& c, OutputStream&
out);
332 SpvId writeVectorConstructor(
const ConstructorCompound& c, OutputStream&
out);
334 SpvId writeCompositeConstructor(
const AnyConstructor& c, OutputStream&
out);
336 SpvId writeConstructorDiagonalMatrix(
const ConstructorDiagonalMatrix& c, OutputStream&
out);
338 SpvId writeConstructorMatrixResize(
const ConstructorMatrixResize& c, OutputStream&
out);
340 SpvId writeConstructorScalarCast(
const ConstructorScalarCast& c, OutputStream&
out);
342 SpvId writeConstructorSplat(
const ConstructorSplat& c, OutputStream&
out);
344 SpvId writeConstructorCompoundCast(
const ConstructorCompoundCast& c, OutputStream&
out);
346 SpvId writeFieldAccess(
const FieldAccess&
f, OutputStream&
out);
348 SpvId writeSwizzle(
const Expression& baseExpr,
352 SpvId writeSwizzle(
const Swizzle& swizzle, OutputStream&
out);
364 SpvOp_ mergeOperator, OutputStream&
out);
376 SpvId mergeComparisons(
SpvId comparison,
SpvId allComparisons, Operator op, OutputStream&
out);
380 SpvId writeDecomposedMatrixVectorMultiply(
const Type& leftType,
382 const Type& rightType,
384 const Type& resultType,
387 SpvId writeComponentwiseMatrixUnary(
const Type& operandType,
395 SpvId writeBinaryOperationComponentwiseIfMatrix(
const Type& resultType,
const Type& operandType,
401 SpvId writeBinaryOperation(
const Type& resultType,
const Type& operandType,
SpvId lhs,
405 SpvId writeBinaryOperation(
const Type& resultType,
const Type& operandType,
SpvId lhs,
406 SpvId rhs,
bool writeComponentwiseIfMatrix,
SpvOp_ ifFloat,
411 SpvId writeBinaryExpression(
const Type& leftType,
SpvId lhs, Operator op,
415 SpvId writeBinaryExpression(
const BinaryExpression&
b, OutputStream&
out);
417 SpvId writeTernaryExpression(
const TernaryExpression& t, OutputStream&
out);
419 SpvId writeIndexExpression(
const IndexExpression& expr, OutputStream&
out);
421 SpvId writeLogicalAnd(
const Expression& left,
const Expression& right, OutputStream&
out);
423 SpvId writeLogicalOr(
const Expression& left,
const Expression& right, OutputStream&
out);
425 SpvId writePrefixExpression(
const PrefixExpression&
p, OutputStream&
out);
427 SpvId writePostfixExpression(
const PostfixExpression&
p, OutputStream&
out);
429 SpvId writeLiteral(
const Literal&
f);
433 void writeStatement(
const Statement&
s, OutputStream&
out);
435 void writeBlock(
const Block&
b, OutputStream&
out);
437 void writeIfStatement(
const IfStatement& stmt, OutputStream&
out);
439 void writeForStatement(
const ForStatement&
f, OutputStream&
out);
441 void writeDoStatement(
const DoStatement&
d, OutputStream&
out);
443 void writeSwitchStatement(
const SwitchStatement&
s, OutputStream&
out);
445 void writeReturnStatement(
const ReturnStatement& r, OutputStream&
out);
447 void writeCapabilities(OutputStream&
out);
449 void writeInstructions(
const Program& program, OutputStream&
out);
453 void writeWord(int32_t
word, OutputStream&
out);
455 void writeString(std::string_view
s, OutputStream&
out);
457 void writeInstruction(
SpvOp_ opCode, OutputStream&
out);
459 void writeInstruction(
SpvOp_ opCode, std::string_view
string, OutputStream&
out);
461 void writeInstruction(
SpvOp_ opCode, int32_t word1, OutputStream&
out);
463 void writeInstruction(
SpvOp_ opCode, int32_t word1, std::string_view
string,
466 void writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2, std::string_view
string,
469 void writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2, OutputStream&
out);
471 void writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3,
474 void writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
477 void writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
478 int32_t word5, OutputStream&
out);
480 void writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
481 int32_t word5, int32_t word6, OutputStream&
out);
483 void writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
484 int32_t word5, int32_t word6, int32_t word7, OutputStream&
out);
486 void writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
487 int32_t word5, int32_t word6, int32_t word7, int32_t word8,
495 SpvId writeInstruction(
503 bool operator==(
const Instruction& that)
const;
507 static Instruction BuildInstructionKey(
SpvOp_ opCode,
528 Instruction* resultTypeForInstruction(
const Instruction& instr);
529 int numComponentsForVecInstruction(
const Instruction& instr);
532 struct ConditionalOpCounts {
536 ConditionalOpCounts getConditionalOpCounts();
537 void pruneConditionalOps(ConditionalOpCounts
ops);
539 enum StraightLineLabelType {
550 kBranchIsOnPreviousLine,
553 enum BranchingLabelType {
563 kBranchesOnBothSides,
565 void writeLabel(
SpvId label, StraightLineLabelType
type, OutputStream&
out);
566 void writeLabel(
SpvId label, BranchingLabelType
type, ConditionalOpCounts
ops,
570 MemoryLayout memoryLayoutForVariable(
const Variable&)
const;
572 struct EntrypointAdapter {
573 std::unique_ptr<FunctionDefinition> entrypointDef;
574 std::unique_ptr<FunctionDeclaration> entrypointDecl;
577 EntrypointAdapter writeEntrypointAdapter(
const FunctionDeclaration&
main);
579 struct UniformBuffer {
580 std::unique_ptr<InterfaceBlock> fInterfaceBlock;
581 std::unique_ptr<Variable> fInnerVariable;
582 std::unique_ptr<Type> fStruct;
585 void writeUniformBuffer(SymbolTable* topLevelSymbolTable);
587 void addRTFlipUniform(Position
pos);
589 std::unique_ptr<Expression> identifier(std::string_view
name);
591 std::tuple<const Variable*, const Variable*> synthesizeTextureAndSampler(
592 const Variable& combinedSampler);
596 uint64_t fCapabilities = 0;
598 SpvId fGLSLExtendedInstructions;
600 IntrinsicOpcodeKind opKind;
610 StringStream fGlobalInitializersBuffer;
611 StringStream fConstantBuffer;
612 StringStream fVariableBuffer;
613 StringStream fNameBuffer;
614 StringStream fDecorationBuffer;
618 bool fUseTextureSamplerPairs =
false;
619 struct SynthesizedTextureSamplerPair {
624 std::string fTextureName;
625 std::string fSamplerName;
626 std::unique_ptr<Variable> fTexture;
627 std::unique_ptr<Variable> fSampler;
630 fSynthesizedSamplerMap;
660 SpvId fCurrentBlock = 0;
663 bool fWroteRTFlip =
false;
665 SymbolTable fSynthetics{
true};
668 UniformBuffer fUniformBuffer;
669 std::vector<const VarDeclaration*> fTopLevelUniforms;
682 return fOp == that.fOp &&
683 fResultKind == that.fResultKind &&
684 fWords == that.fWords;
689 uint32_t
hash =
key.fResultKind;
712 return Word{val, Kind::kNumber};
747SPIRVCodeGenerator::Intrinsic SPIRVCodeGenerator::getIntrinsic(
IntrinsicKind ik)
const {
749#define ALL_GLSL(x) Intrinsic{kGLSL_STD_450_IntrinsicOpcodeKind, GLSLstd450 ## x, \
750 GLSLstd450 ## x, GLSLstd450 ## x, GLSLstd450 ## x}
751#define BY_TYPE_GLSL(ifFloat, ifInt, ifUInt) Intrinsic{kGLSL_STD_450_IntrinsicOpcodeKind, \
752 GLSLstd450 ## ifFloat, \
753 GLSLstd450 ## ifInt, \
754 GLSLstd450 ## ifUInt, \
756#define ALL_SPIRV(x) Intrinsic{kSPIRV_IntrinsicOpcodeKind, \
757 SpvOp ## x, SpvOp ## x, SpvOp ## x, SpvOp ## x}
758#define BOOL_SPIRV(x) Intrinsic{kSPIRV_IntrinsicOpcodeKind, \
759 SpvOpUndef, SpvOpUndef, SpvOpUndef, SpvOp ## x}
760#define FLOAT_SPIRV(x) Intrinsic{kSPIRV_IntrinsicOpcodeKind, \
761 SpvOp ## x, SpvOpUndef, SpvOpUndef, SpvOpUndef}
762#define SPECIAL(x) Intrinsic{kSpecial_IntrinsicOpcodeKind, k ## x ## _SpecialIntrinsic, \
763 k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
764 k ## x ## _SpecialIntrinsic}
767 case k_round_IntrinsicKind:
return ALL_GLSL(Round);
768 case k_roundEven_IntrinsicKind:
return ALL_GLSL(RoundEven);
769 case k_trunc_IntrinsicKind:
return ALL_GLSL(Trunc);
770 case k_abs_IntrinsicKind:
return BY_TYPE_GLSL(FAbs, SAbs, SAbs);
771 case k_sign_IntrinsicKind:
return BY_TYPE_GLSL(FSign, SSign, SSign);
772 case k_floor_IntrinsicKind:
return ALL_GLSL(Floor);
773 case k_ceil_IntrinsicKind:
return ALL_GLSL(Ceil);
774 case k_fract_IntrinsicKind:
return ALL_GLSL(Fract);
775 case k_radians_IntrinsicKind:
return ALL_GLSL(Radians);
776 case k_degrees_IntrinsicKind:
return ALL_GLSL(Degrees);
777 case k_sin_IntrinsicKind:
return ALL_GLSL(Sin);
778 case k_cos_IntrinsicKind:
return ALL_GLSL(Cos);
779 case k_tan_IntrinsicKind:
return ALL_GLSL(Tan);
780 case k_asin_IntrinsicKind:
return ALL_GLSL(Asin);
781 case k_acos_IntrinsicKind:
return ALL_GLSL(Acos);
782 case k_atan_IntrinsicKind:
return SPECIAL(Atan);
783 case k_sinh_IntrinsicKind:
return ALL_GLSL(Sinh);
784 case k_cosh_IntrinsicKind:
return ALL_GLSL(Cosh);
785 case k_tanh_IntrinsicKind:
return ALL_GLSL(Tanh);
786 case k_asinh_IntrinsicKind:
return ALL_GLSL(Asinh);
787 case k_acosh_IntrinsicKind:
return ALL_GLSL(Acosh);
788 case k_atanh_IntrinsicKind:
return ALL_GLSL(Atanh);
789 case k_pow_IntrinsicKind:
return ALL_GLSL(Pow);
790 case k_exp_IntrinsicKind:
return ALL_GLSL(Exp);
792 case k_exp2_IntrinsicKind:
return ALL_GLSL(Exp2);
793 case k_log2_IntrinsicKind:
return ALL_GLSL(Log2);
794 case k_sqrt_IntrinsicKind:
return ALL_GLSL(Sqrt);
795 case k_inverse_IntrinsicKind:
return ALL_GLSL(MatrixInverse);
796 case k_outerProduct_IntrinsicKind:
return ALL_SPIRV(OuterProduct);
797 case k_transpose_IntrinsicKind:
return ALL_SPIRV(Transpose);
798 case k_isinf_IntrinsicKind:
return ALL_SPIRV(IsInf);
799 case k_isnan_IntrinsicKind:
return ALL_SPIRV(IsNan);
800 case k_inversesqrt_IntrinsicKind:
return ALL_GLSL(InverseSqrt);
801 case k_determinant_IntrinsicKind:
return ALL_GLSL(Determinant);
802 case k_matrixCompMult_IntrinsicKind:
return SPECIAL(MatrixCompMult);
803 case k_matrixInverse_IntrinsicKind:
return ALL_GLSL(MatrixInverse);
804 case k_mod_IntrinsicKind:
return SPECIAL(Mod);
805 case k_modf_IntrinsicKind:
return ALL_GLSL(Modf);
806 case k_min_IntrinsicKind:
return SPECIAL(
Min);
807 case k_max_IntrinsicKind:
return SPECIAL(Max);
808 case k_clamp_IntrinsicKind:
return SPECIAL(Clamp);
811 case k_mix_IntrinsicKind:
return SPECIAL(
Mix);
812 case k_step_IntrinsicKind:
return SPECIAL(Step);
813 case k_smoothstep_IntrinsicKind:
return SPECIAL(SmoothStep);
814 case k_fma_IntrinsicKind:
return ALL_GLSL(Fma);
815 case k_frexp_IntrinsicKind:
return ALL_GLSL(Frexp);
816 case k_ldexp_IntrinsicKind:
return ALL_GLSL(Ldexp);
818#define PACK(type) case k_pack##type##_IntrinsicKind: return ALL_GLSL(Pack##type); \
819 case k_unpack##type##_IntrinsicKind: return ALL_GLSL(Unpack##type)
827 case k_length_IntrinsicKind:
return ALL_GLSL(Length);
828 case k_distance_IntrinsicKind:
return ALL_GLSL(Distance);
829 case k_cross_IntrinsicKind:
return ALL_GLSL(Cross);
831 case k_faceforward_IntrinsicKind:
return ALL_GLSL(FaceForward);
832 case k_reflect_IntrinsicKind:
return ALL_GLSL(Reflect);
833 case k_refract_IntrinsicKind:
return ALL_GLSL(Refract);
834 case k_bitCount_IntrinsicKind:
return ALL_SPIRV(BitCount);
835 case k_findLSB_IntrinsicKind:
return ALL_GLSL(FindILsb);
836 case k_findMSB_IntrinsicKind:
return BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
837 case k_dFdx_IntrinsicKind:
return FLOAT_SPIRV(DPdx);
838 case k_dFdy_IntrinsicKind:
return SPECIAL(DFdy);
839 case k_fwidth_IntrinsicKind:
return FLOAT_SPIRV(Fwidth);
841 case k_sample_IntrinsicKind:
return SPECIAL(Texture);
842 case k_sampleGrad_IntrinsicKind:
return SPECIAL(TextureGrad);
843 case k_sampleLod_IntrinsicKind:
return SPECIAL(TextureLod);
844 case k_subpassLoad_IntrinsicKind:
return SPECIAL(SubpassLoad);
846 case k_textureRead_IntrinsicKind:
return SPECIAL(TextureRead);
847 case k_textureWrite_IntrinsicKind:
return SPECIAL(TextureWrite);
848 case k_textureWidth_IntrinsicKind:
return SPECIAL(TextureWidth);
849 case k_textureHeight_IntrinsicKind:
return SPECIAL(TextureHeight);
851 case k_floatBitsToInt_IntrinsicKind:
return ALL_SPIRV(Bitcast);
852 case k_floatBitsToUint_IntrinsicKind:
return ALL_SPIRV(Bitcast);
853 case k_intBitsToFloat_IntrinsicKind:
return ALL_SPIRV(Bitcast);
854 case k_uintBitsToFloat_IntrinsicKind:
return ALL_SPIRV(Bitcast);
857 case k_all_IntrinsicKind:
return BOOL_SPIRV(All);
858 case k_not_IntrinsicKind:
return BOOL_SPIRV(LogicalNot);
860 case k_equal_IntrinsicKind:
861 return Intrinsic{kSPIRV_IntrinsicOpcodeKind,
866 case k_notEqual_IntrinsicKind:
867 return Intrinsic{kSPIRV_IntrinsicOpcodeKind,
872 case k_lessThan_IntrinsicKind:
873 return Intrinsic{kSPIRV_IntrinsicOpcodeKind,
878 case k_lessThanEqual_IntrinsicKind:
879 return Intrinsic{kSPIRV_IntrinsicOpcodeKind,
884 case k_greaterThan_IntrinsicKind:
885 return Intrinsic{kSPIRV_IntrinsicOpcodeKind,
890 case k_greaterThanEqual_IntrinsicKind:
891 return Intrinsic{kSPIRV_IntrinsicOpcodeKind,
897 case k_atomicAdd_IntrinsicKind:
return SPECIAL(AtomicAdd);
898 case k_atomicLoad_IntrinsicKind:
return SPECIAL(AtomicLoad);
899 case k_atomicStore_IntrinsicKind:
return SPECIAL(AtomicStore);
901 case k_storageBarrier_IntrinsicKind:
return SPECIAL(StorageBarrier);
902 case k_workgroupBarrier_IntrinsicKind:
return SPECIAL(WorkgroupBarrier);
904 case k_loadFloatBuffer_IntrinsicKind:
return SPECIAL(LoadFloatBuffer);
906 return Intrinsic{kInvalid_IntrinsicOpcodeKind, 0, 0, 0, 0};
910void SPIRVCodeGenerator::writeWord(int32_t
word, OutputStream&
out) {
915 return (
type.isScalar() ||
type.isVector() ||
type.isMatrix()) &&
916 type.componentType().isFloat();
920 return (
type.isScalar() ||
type.isVector()) &&
type.componentType().isSigned();
924 return (
type.isScalar() ||
type.isVector()) &&
type.componentType().isUnsigned();
928 return (
type.isScalar() ||
type.isVector()) &&
type.componentType().isBoolean();
1016void SPIRVCodeGenerator::writeOpCode(
SpvOp_ opCode,
int length, OutputStream&
out) {
1019 bool foundDeadCode =
false;
1022 foundDeadCode = (fCurrentBlock == 0);
1025 foundDeadCode = (fCurrentBlock == 0);
1028 if (foundDeadCode) {
1031 this->writeLabel(this->nextId(
nullptr), kBranchlessBlock,
out);
1034 this->writeWord((
length << 16) | opCode,
out);
1037void SPIRVCodeGenerator::writeLabel(
SpvId label, StraightLineLabelType, OutputStream&
out) {
1040 fCurrentBlock = label;
1044void SPIRVCodeGenerator::writeLabel(
SpvId label, BranchingLabelType
type,
1045 ConditionalOpCounts
ops, OutputStream&
out) {
1047 case kBranchIsBelow:
1048 case kBranchesOnBothSides:
1052 fStoreCache.
reset();
1055 case kBranchIsAbove:
1059 this->pruneConditionalOps(
ops);
1064 this->writeLabel(label, kBranchlessBlock,
out);
1067void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, OutputStream&
out) {
1068 this->writeOpCode(opCode, 1,
out);
1071void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, OutputStream&
out) {
1072 this->writeOpCode(opCode, 2,
out);
1073 this->writeWord(word1,
out);
1076void SPIRVCodeGenerator::writeString(std::string_view
s, OutputStream&
out) {
1077 out.write(
s.data(),
s.length());
1078 switch (
s.length() % 4) {
1089 this->writeWord(0,
out);
1094void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, std::string_view
string,
1095 OutputStream&
out) {
1096 this->writeOpCode(opCode, 1 + (
string.
length() + 4) / 4,
out);
1097 this->writeString(
string,
out);
1100void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, std::string_view
string,
1101 OutputStream&
out) {
1102 this->writeOpCode(opCode, 2 + (
string.
length() + 4) / 4,
out);
1103 this->writeWord(word1,
out);
1104 this->writeString(
string,
out);
1107void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2,
1108 std::string_view
string, OutputStream&
out) {
1109 this->writeOpCode(opCode, 3 + (
string.
length() + 4) / 4,
out);
1110 this->writeWord(word1,
out);
1111 this->writeWord(word2,
out);
1112 this->writeString(
string,
out);
1115void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2,
1116 OutputStream&
out) {
1117 this->writeOpCode(opCode, 3,
out);
1118 this->writeWord(word1,
out);
1119 this->writeWord(word2,
out);
1122void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2,
1123 int32_t word3, OutputStream&
out) {
1124 this->writeOpCode(opCode, 4,
out);
1125 this->writeWord(word1,
out);
1126 this->writeWord(word2,
out);
1127 this->writeWord(word3,
out);
1130void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2,
1131 int32_t word3, int32_t word4, OutputStream&
out) {
1132 this->writeOpCode(opCode, 5,
out);
1133 this->writeWord(word1,
out);
1134 this->writeWord(word2,
out);
1135 this->writeWord(word3,
out);
1136 this->writeWord(word4,
out);
1139void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2,
1140 int32_t word3, int32_t word4, int32_t word5,
1141 OutputStream&
out) {
1142 this->writeOpCode(opCode, 6,
out);
1143 this->writeWord(word1,
out);
1144 this->writeWord(word2,
out);
1145 this->writeWord(word3,
out);
1146 this->writeWord(word4,
out);
1147 this->writeWord(word5,
out);
1150void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2,
1151 int32_t word3, int32_t word4, int32_t word5,
1152 int32_t word6, OutputStream&
out) {
1153 this->writeOpCode(opCode, 7,
out);
1154 this->writeWord(word1,
out);
1155 this->writeWord(word2,
out);
1156 this->writeWord(word3,
out);
1157 this->writeWord(word4,
out);
1158 this->writeWord(word5,
out);
1159 this->writeWord(word6,
out);
1162void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2,
1163 int32_t word3, int32_t word4, int32_t word5,
1164 int32_t word6, int32_t word7, OutputStream&
out) {
1165 this->writeOpCode(opCode, 8,
out);
1166 this->writeWord(word1,
out);
1167 this->writeWord(word2,
out);
1168 this->writeWord(word3,
out);
1169 this->writeWord(word4,
out);
1170 this->writeWord(word5,
out);
1171 this->writeWord(word6,
out);
1172 this->writeWord(word7,
out);
1175void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2,
1176 int32_t word3, int32_t word4, int32_t word5,
1177 int32_t word6, int32_t word7, int32_t word8,
1178 OutputStream&
out) {
1179 this->writeOpCode(opCode, 9,
out);
1180 this->writeWord(word1,
out);
1181 this->writeWord(word2,
out);
1182 this->writeWord(word3,
out);
1183 this->writeWord(word4,
out);
1184 this->writeWord(word5,
out);
1185 this->writeWord(word6,
out);
1186 this->writeWord(word7,
out);
1187 this->writeWord(word8,
out);
1190SPIRVCodeGenerator::Instruction SPIRVCodeGenerator::BuildInstructionKey(
SpvOp_ opCode,
1195 key.fWords.resize(words.
size());
1198 for (
int index = 0; index < words.
size(); ++index) {
1199 const Word&
word = words[index];
1200 key.fWords[index] =
word.fValue;
1201 if (
word.isResult()) {
1210SpvId SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode,
1212 OutputStream&
out) {
1218 Instruction
key = BuildInstructionKey(opCode, words);
1219 if (
SpvId* cachedOp = fOpCache.find(
key)) {
1224 Precision precision = Precision::kDefault;
1226 switch (
key.fResultKind) {
1227 case Word::Kind::kUniqueResult:
1229 result = this->nextId(Precision::kDefault);
1238 case Word::Kind::kRelaxedPrecisionResult:
1239 precision = Precision::kRelaxed;
1242 case Word::Kind::kKeyedResult:
1245 case Word::Kind::kDefaultPrecisionResult:
1247 result = this->nextId(precision);
1263 this->writeOpCode(opCode, words.
size() + 1,
out);
1264 for (
const Word&
word : words) {
1265 if (
word.isResult()) {
1269 this->writeWord(
word.fValue,
out);
1278 Precision precision,
1280 OutputStream&
out) {
1282 if (
SpvId* cachedOp = fStoreCache.
find(pointer)) {
1295 OutputStream&
out) {
1307SpvId SPIRVCodeGenerator::writeOpConstantTrue(
const Type&
type) {
1313SpvId SPIRVCodeGenerator::writeOpConstantFalse(
const Type&
type) {
1319SpvId SPIRVCodeGenerator::writeOpConstant(
const Type&
type, int32_t valueBits) {
1320 return this->writeInstruction(
1326SpvId SPIRVCodeGenerator::writeOpConstantComposite(
const Type&
type,
1331 words.push_back(this->getType(
type));
1334 words.push_back(
value);
1340 Instruction* instr = fSpvIdCache.
find(
value);
1344 switch (instr->fOp) {
1353 for (
int i = 2;
i < instr->fWords.size(); ++
i) {
1354 if (!this->toConstants(instr->fWords[
i], constants)) {
1367 if (!this->toConstants(
value, constants)) {
1374SpvId SPIRVCodeGenerator::writeOpCompositeConstruct(
const Type&
type,
1376 OutputStream&
out) {
1378 if (
type.isVector()) {
1382 return this->writeOpConstantComposite(
type, constants);
1387 if (
type.isMatrix()) {
1394 for (
int index=0; index <
type.columns(); ++index) {
1397 columnIDs.
push_back(this->writeOpConstantComposite(vecType, columnConstants));
1400 return this->writeOpConstantComposite(
type, columnIDs);
1405 words.push_back(this->getType(
type));
1408 words.push_back(
value);
1414SPIRVCodeGenerator::Instruction* SPIRVCodeGenerator::resultTypeForInstruction(
1415 const Instruction& instr) {
1421 switch (instr.fOp) {
1436 Instruction* typeInstr = fSpvIdCache.
find(instr.fWords[resultTypeWord]);
1441int SPIRVCodeGenerator::numComponentsForVecInstruction(
const Instruction& instr) {
1443 Instruction* typeInstr = this->resultTypeForInstruction(instr);
1454SpvId SPIRVCodeGenerator::toComponent(
SpvId id,
int component) {
1455 Instruction* instr = fSpvIdCache.
find(
id);
1462 return instr->fWords[2 + component];
1467 Instruction* composedType = fSpvIdCache.
find(instr->fWords[0]);
1473 return instr->fWords[2 + component];
1478 for (
int index = 2; index < instr->fWords.size(); ++index) {
1479 int32_t currentWord = instr->fWords[index];
1482 Instruction* subinstr = fSpvIdCache.
find(currentWord);
1487 int numComponents = this->numComponentsForVecInstruction(*subinstr);
1488 if (component < numComponents) {
1489 if (numComponents == 1) {
1495 return this->toComponent(currentWord, component);
1499 component -= numComponents;
1501 SkDEBUGFAIL(
"component index goes past the end of this composite value");
1507SpvId SPIRVCodeGenerator::writeOpCompositeExtract(
const Type&
type,
1510 OutputStream&
out) {
1516 return this->writeInstruction(
1522SpvId SPIRVCodeGenerator::writeOpCompositeExtract(
const Type&
type,
1526 OutputStream&
out) {
1530 return this->writeOpCompositeExtract(
type,
result, componentB,
out);
1533 {this->getType(
type),
1541void SPIRVCodeGenerator::writeCapabilities(OutputStream&
out) {
1543 if (fCapabilities & bit) {
1551 return this->nextId(
type &&
type->hasPrecision() && !
type->highPrecision()
1552 ? Precision::kRelaxed
1553 : Precision::kDefault);
1556SpvId SPIRVCodeGenerator::nextId(Precision precision) {
1557 if (precision == Precision::kRelaxed && !
fProgram.
fConfig->fSettings.fForceHighPrecision) {
1564SpvId SPIRVCodeGenerator::writeStruct(
const Type&
type,
const MemoryLayout& memoryLayout) {
1566 if (
SpvId* cachedStructId = fStructMap.find(&
type)) {
1567 return *cachedStructId;
1574 for (
const auto&
f :
type.fields()) {
1575 words.push_back(this->getType(*
f.fType,
f.fLayout, memoryLayout));
1578 this->writeInstruction(
SpvOpName, resultId,
type.name(), fNameBuffer);
1579 fStructMap.set(&
type, resultId);
1582 for (int32_t
i = 0;
i < (int32_t)
type.fields().size();
i++) {
1583 const Field& field =
type.fields()[
i];
1584 if (!memoryLayout.isSupported(*field.fType)) {
1586 "' is not permitted here");
1589 size_t size = memoryLayout.size(*field.fType);
1590 size_t alignment = memoryLayout.alignment(*field.fType);
1591 const Layout& fieldLayout = field.fLayout;
1592 if (fieldLayout.fOffset >= 0) {
1593 if (fieldLayout.fOffset < (
int)
offset) {
1597 if (fieldLayout.fOffset % alignment) {
1599 "offset of field '" + std::string(field.fName) +
1602 offset = fieldLayout.fOffset;
1604 size_t mod =
offset % alignment;
1606 offset += alignment - mod;
1609 this->writeInstruction(
SpvOpMemberName, resultId,
i, field.fName, fNameBuffer);
1610 this->writeFieldLayout(fieldLayout, resultId,
i);
1611 if (field.fLayout.fBuiltin < 0) {
1615 if (field.fType->isMatrix()) {
1619 (
SpvId) memoryLayout.stride(*field.fType),
1622 if (!field.fType->highPrecision()) {
1627 if ((field.fType->isArray() || field.fType->isStruct()) &&
offset % alignment != 0) {
1641 switch (
flags.value()) {
1658SpvId SPIRVCodeGenerator::getType(
const Type& rawType,
1659 const Layout& typeLayout,
1660 const MemoryLayout& memoryLayout) {
1663 switch (
type->typeKind()) {
1669 if (
type->isBoolean()) {
1672 if (
type->isSigned()) {
1673 return this->writeInstruction(
1678 if (
type->isUnsigned()) {
1679 return this->writeInstruction(
1684 if (
type->isFloat()) {
1685 return this->writeInstruction(
1690 SkDEBUGFAILF(
"unrecognized scalar type '%s'",
type->description().c_str());
1694 SpvId scalarTypeId = this->getType(
type->componentType(), typeLayout, memoryLayout);
1695 return this->writeInstruction(
1704 return this->writeInstruction(
1710 if (!memoryLayout.isSupported(*
type)) {
1712 "' is not permitted here");
1715 size_t stride = memoryLayout.stride(*
type);
1716 SpvId typeId = this->getType(
type->componentType(), typeLayout, memoryLayout);
1718 if (
type->isUnsizedArray()) {
1734 return this->writeStruct(*
type, memoryLayout);
1743 SpvId imageTypeId = this->getType(
type->textureType(), typeLayout, memoryLayout);
1785SpvId SPIRVCodeGenerator::getFunctionType(
const FunctionDeclaration&
function) {
1788 words.push_back(this->getType(
function.returnType()));
1789 for (
const Variable* parameter :
function.parameters()) {
1790 if (fUseTextureSamplerPairs && parameter->type().isSampler()) {
1791 words.push_back(this->getFunctionParameterType(parameter->type().textureType(),
1792 parameter->layout()));
1796 words.push_back(this->getFunctionParameterType(parameter->type(), parameter->layout()));
1802SpvId SPIRVCodeGenerator::getFunctionParameterType(
const Type& parameterType,
1803 const Layout& parameterLayout) {
1843 return this->getPointerType(parameterType,
1845 this->memoryLayoutForStorageClass(storageClass),
1850 return this->getPointerType(
type,
1852 this->memoryLayoutForStorageClass(storageClass),
1857 const Layout& typeLayout,
1858 const MemoryLayout& memoryLayout,
1863 this->getType(
type, typeLayout, memoryLayout)},
1867SpvId SPIRVCodeGenerator::writeExpression(
const Expression& expr, OutputStream&
out) {
1868 switch (expr.kind()) {
1869 case Expression::Kind::kBinary:
1870 return this->writeBinaryExpression(expr.as<BinaryExpression>(),
out);
1871 case Expression::Kind::kConstructorArrayCast:
1872 return this->writeExpression(*expr.as<ConstructorArrayCast>().argument(),
out);
1873 case Expression::Kind::kConstructorArray:
1874 case Expression::Kind::kConstructorStruct:
1875 return this->writeCompositeConstructor(expr.asAnyConstructor(),
out);
1876 case Expression::Kind::kConstructorDiagonalMatrix:
1877 return this->writeConstructorDiagonalMatrix(expr.as<ConstructorDiagonalMatrix>(),
out);
1878 case Expression::Kind::kConstructorMatrixResize:
1879 return this->writeConstructorMatrixResize(expr.as<ConstructorMatrixResize>(),
out);
1880 case Expression::Kind::kConstructorScalarCast:
1881 return this->writeConstructorScalarCast(expr.as<ConstructorScalarCast>(),
out);
1882 case Expression::Kind::kConstructorSplat:
1883 return this->writeConstructorSplat(expr.as<ConstructorSplat>(),
out);
1884 case Expression::Kind::kConstructorCompound:
1885 return this->writeConstructorCompound(expr.as<ConstructorCompound>(),
out);
1886 case Expression::Kind::kConstructorCompoundCast:
1887 return this->writeConstructorCompoundCast(expr.as<ConstructorCompoundCast>(),
out);
1890 case Expression::Kind::kFieldAccess:
1891 return this->writeFieldAccess(expr.as<FieldAccess>(),
out);
1892 case Expression::Kind::kFunctionCall:
1893 return this->writeFunctionCall(expr.as<FunctionCall>(),
out);
1895 return this->writeLiteral(expr.as<Literal>());
1896 case Expression::Kind::kPrefix:
1897 return this->writePrefixExpression(expr.as<PrefixExpression>(),
out);
1898 case Expression::Kind::kPostfix:
1899 return this->writePostfixExpression(expr.as<PostfixExpression>(),
out);
1900 case Expression::Kind::kSwizzle:
1901 return this->writeSwizzle(expr.as<Swizzle>(),
out);
1902 case Expression::Kind::kVariableReference:
1903 return this->writeVariableReference(expr.as<VariableReference>(),
out);
1904 case Expression::Kind::kTernary:
1905 return this->writeTernaryExpression(expr.as<TernaryExpression>(),
out);
1907 return this->writeIndexExpression(expr.as<IndexExpression>(),
out);
1908 case Expression::Kind::kSetting:
1909 return this->writeExpression(*expr.as<Setting>().toLiteral(
fCaps),
out);
1911 SkDEBUGFAILF(
"unsupported expression: %s", expr.description().c_str());
1917SpvId SPIRVCodeGenerator::writeIntrinsicCall(
const FunctionCall& c, OutputStream&
out) {
1918 const FunctionDeclaration&
function = c.function();
1919 Intrinsic intrinsic = this->getIntrinsic(
function.intrinsicKind());
1920 if (intrinsic.opKind == kInvalid_IntrinsicOpcodeKind) {
1925 const ExpressionArray& arguments = c.arguments();
1926 int32_t intrinsicId = intrinsic.floatOp;
1927 if (!arguments.empty()) {
1928 const Type&
type = arguments[0]->type();
1929 if (intrinsic.opKind == kSpecial_IntrinsicOpcodeKind) {
1933 intrinsic.unsignedOp, intrinsic.boolOp);
1936 switch (intrinsic.opKind) {
1937 case kGLSL_STD_450_IntrinsicOpcodeKind: {
1941 std::vector<TempVar> tempVars;
1942 for (
int i = 0;
i < arguments.size();
i++) {
1943 argumentIds.
push_back(this->writeFunctionCallArgument(c,
i, &tempVars,
out));
1946 this->writeWord(this->getType(c.type()),
out);
1948 this->writeWord(fGLSLExtendedInstructions,
out);
1949 this->writeWord(intrinsicId,
out);
1950 for (
SpvId id : argumentIds) {
1951 this->writeWord(
id,
out);
1953 this->copyBackTempVars(tempVars,
out);
1956 case kSPIRV_IntrinsicOpcodeKind: {
1958 if (intrinsicId ==
SpvOpDot && arguments[0]->
type().isScalar()) {
1964 std::vector<TempVar> tempVars;
1965 for (
int i = 0;
i < arguments.size();
i++) {
1966 argumentIds.
push_back(this->writeFunctionCallArgument(c,
i, &tempVars,
out));
1968 if (!c.type().isVoid()) {
1969 this->writeOpCode((
SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(),
out);
1970 this->writeWord(this->getType(c.type()),
out);
1973 this->writeOpCode((
SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(),
out);
1975 for (
SpvId id : argumentIds) {
1976 this->writeWord(
id,
out);
1978 this->copyBackTempVars(tempVars,
out);
1981 case kSpecial_IntrinsicOpcodeKind:
1982 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId,
out);
1990SpvId SPIRVCodeGenerator::vectorize(
const Expression& arg,
int vectorSize, OutputStream&
out) {
1991 SkASSERT(vectorSize >= 1 && vectorSize <= 4);
1992 const Type& argType = arg.type();
1993 if (argType.isScalar() && vectorSize > 1) {
1994 ConstructorSplat splat{arg.fPosition,
1995 argType.toCompound(
fContext, vectorSize, 1),
1997 return this->writeConstructorSplat(splat,
out);
2000 SkASSERT(vectorSize == argType.columns());
2001 return this->writeExpression(arg,
out);
2006 for (
const auto&
a :
args) {
2007 if (
a->type().isVector()) {
2008 if (vectorSize > 1) {
2009 SkASSERT(
a->type().columns() == vectorSize);
2011 vectorSize =
a->type().columns();
2017 for (
const auto& arg :
args) {
2018 result.push_back(this->vectorize(*arg, vectorSize,
out));
2023void SPIRVCodeGenerator::writeGLSLExtendedInstruction(
const Type&
type,
SpvId id,
SpvId floatInst,
2026 OutputStream&
out) {
2028 this->writeWord(this->getType(
type),
out);
2029 this->writeWord(
id,
out);
2030 this->writeWord(fGLSLExtendedInstructions,
out);
2033 this->writeWord(
a,
out);
2037SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(
const FunctionCall& c, SpecialIntrinsic kind,
2038 OutputStream&
out) {
2039 const ExpressionArray& arguments = c.arguments();
2040 const Type& callType = c.type();
2043 case kAtan_SpecialIntrinsic: {
2045 for (
const std::unique_ptr<Expression>& arg : arguments) {
2046 argumentIds.
push_back(this->writeExpression(*arg,
out));
2049 this->writeWord(this->getType(callType),
out);
2051 this->writeWord(fGLSLExtendedInstructions,
out);
2053 for (
SpvId id : argumentIds) {
2054 this->writeWord(
id,
out);
2058 case kSampledImage_SpecialIntrinsic: {
2060 SpvId img = this->writeExpression(*arguments[0],
out);
2061 SpvId sampler = this->writeExpression(*arguments[1],
out);
2063 this->getType(callType),
2070 case kSubpassLoad_SpecialIntrinsic: {
2071 SpvId img = this->writeExpression(*arguments[0],
out);
2072 ExpressionArray
args;
2073 args.reserve_exact(2);
2077 SpvId coords = this->writeExpression(ctor,
out);
2078 if (arguments.size() == 1) {
2080 this->getType(callType),
2087 SpvId sample = this->writeExpression(*arguments[1],
out);
2089 this->getType(callType),
2099 case kTexture_SpecialIntrinsic: {
2101 const Type& arg1Type = arguments[1]->type();
2102 switch (arguments[0]->
type().dimensions()) {
2131 SpvId sampler = this->writeExpression(*arguments[0],
out);
2132 SpvId uv = this->writeExpression(*arguments[1],
out);
2133 if (arguments.size() == 3) {
2134 this->writeInstruction(op,
type,
result, sampler, uv,
2136 this->writeExpression(*arguments[2],
out),
2143 this->writeInstruction(op,
type,
result, sampler, uv,
2146 this->writeInstruction(op,
type,
result, sampler, uv,
2152 case kTextureGrad_SpecialIntrinsic: {
2160 SpvId sampler = this->writeExpression(*arguments[0],
out);
2161 SpvId uv = this->writeExpression(*arguments[1],
out);
2162 SpvId dPdx = this->writeExpression(*arguments[2],
out);
2163 SpvId dPdy = this->writeExpression(*arguments[3],
out);
2168 case kTextureLod_SpecialIntrinsic: {
2173 const Type& arg1Type = arguments[1]->type();
2180 SpvId sampler = this->writeExpression(*arguments[0],
out);
2181 SpvId uv = this->writeExpression(*arguments[1],
out);
2182 this->writeInstruction(op,
type,
result, sampler, uv,
2184 this->writeExpression(*arguments[2],
out),
2188 case kTextureRead_SpecialIntrinsic: {
2194 SpvId coord = this->writeExpression(*arguments[1],
out);
2196 const Type& arg0Type = arguments[0]->type();
2199 switch (arg0Type.textureAccess()) {
2212 SkDEBUGFAIL(
"'textureRead' called on writeonly texture type");
2218 case kTextureWrite_SpecialIntrinsic: {
2224 SpvId coord = this->writeExpression(*arguments[1],
out);
2225 SpvId texel = this->writeExpression(*arguments[2],
out);
2230 case kTextureWidth_SpecialIntrinsic:
2231 case kTextureHeight_SpecialIntrinsic: {
2236 SpvId dims = this->nextId(
nullptr);
2241 int32_t index = (kind == kTextureWidth_SpecialIntrinsic) ? 0 : 1;
2245 case kMod_SpecialIntrinsic: {
2248 const Type& operandType = arguments[0]->type();
2251 this->writeOpCode(op, 5,
out);
2252 this->writeWord(this->getType(operandType),
out);
2254 this->writeWord(
args[0],
out);
2255 this->writeWord(
args[1],
out);
2258 case kDFdy_SpecialIntrinsic: {
2259 SpvId fn = this->writeExpression(*arguments[0],
out);
2261 this->writeWord(this->getType(callType),
out);
2263 this->writeWord(fn,
out);
2265 this->addRTFlipUniform(c.fPosition);
2267 for (
int index = 0; index < callType.columns(); ++index) {
2271 componentArray,
out);
2272 SpvId flipped = this->nextId(&callType);
2273 this->writeInstruction(
SpvOpFMul, this->getType(callType), flipped,
result,
2279 case kClamp_SpecialIntrinsic: {
2286 case kMax_SpecialIntrinsic: {
2293 case kMin_SpecialIntrinsic: {
2300 case kMix_SpecialIntrinsic: {
2303 if (arguments[2]->
type().componentType().isBoolean()) {
2305 SpvId falseId = this->writeExpression(*arguments[0],
out);
2306 SpvId trueId = this->writeExpression(*arguments[1],
out);
2307 SpvId conditionId = this->writeExpression(*arguments[2],
out);
2309 conditionId, trueId, falseId,
out);
2316 case kSaturate_SpecialIntrinsic: {
2318 ExpressionArray finalArgs;
2319 finalArgs.reserve_exact(3);
2320 finalArgs.push_back(arguments[0]->clone());
2328 case kSmoothStep_SpecialIntrinsic: {
2335 case kStep_SpecialIntrinsic: {
2342 case kMatrixCompMult_SpecialIntrinsic: {
2344 SpvId lhs = this->writeExpression(*arguments[0],
out);
2345 SpvId rhs = this->writeExpression(*arguments[1],
out);
2349 case kAtomicAdd_SpecialIntrinsic:
2350 case kAtomicLoad_SpecialIntrinsic:
2351 case kAtomicStore_SpecialIntrinsic:
2354 case kStorageBarrier_SpecialIntrinsic:
2355 case kWorkgroupBarrier_SpecialIntrinsic: {
2360 int32_t memSemMask = (kind == kStorageBarrier_SpecialIntrinsic)
2373 case kLoadFloatBuffer_SpecialIntrinsic: {
2378 c.arguments()[0]->clone());
2380 result = this->writeExpression(*indexExpression,
out);
2387SpvId SPIRVCodeGenerator::writeAtomicIntrinsic(
const FunctionCall& c,
2388 SpecialIntrinsic kind,
2390 OutputStream&
out) {
2391 const ExpressionArray& arguments = c.arguments();
2394 std::unique_ptr<LValue> atomicPtr = this->getLValue(*arguments[0],
out);
2395 SpvId atomicPtrId = atomicPtr->getPointer();
2396 if (atomicPtrId ==
NA) {
2397 SkDEBUGFAILF(
"atomic intrinsic expected a pointer argument: %s",
2398 arguments[0]->description().c_str());
2408 switch (atomicPtr->storageClass()) {
2418 SkDEBUGFAILF(
"atomic argument has invalid storage class: %d",
2419 atomicPtr->storageClass());
2425 SpvId relaxedMemoryOrderId =
2429 case kAtomicAdd_SpecialIntrinsic:
2432 this->getType(c.type()),
2436 relaxedMemoryOrderId,
2437 this->writeExpression(*arguments[1],
out),
2440 case kAtomicLoad_SpecialIntrinsic:
2443 this->getType(c.type()),
2447 relaxedMemoryOrderId,
2450 case kAtomicStore_SpecialIntrinsic:
2455 relaxedMemoryOrderId,
2456 this->writeExpression(*arguments[1],
out),
2466SpvId SPIRVCodeGenerator::writeFunctionCallArgument(
const FunctionCall&
call,
2468 std::vector<TempVar>* tempVars,
2470 SpvId* outSynthesizedSamplerId) {
2471 const FunctionDeclaration& funcDecl =
call.function();
2472 const Expression& arg = *
call.arguments()[argIndex];
2473 ModifierFlags paramFlags = funcDecl.parameters()[argIndex]->modifierFlags();
2481 if (
is_out(paramFlags)) {
2482 std::unique_ptr<LValue> lv = this->getLValue(arg,
out);
2487 if (
is_in(paramFlags)) {
2488 tmpValueId = lv->load(
out);
2490 tmpVar = this->nextId(&arg.type());
2491 tempVars->push_back(TempVar{tmpVar, &arg.type(), std::move(lv)});
2492 }
else if (funcDecl.isIntrinsic()) {
2494 return this->writeExpression(arg,
out);
2495 }
else if (arg.is<VariableReference>() &&
2506 const Variable* var = arg.as<VariableReference>().variable();
2509 if (fUseTextureSamplerPairs && var->type().isSampler()) {
2510 if (
const auto*
p = fSynthesizedSamplerMap.find(var)) {
2513 SpvId* img = fVariableMap.find((*p)->fTexture.get());
2514 SpvId* sampler = fVariableMap.find((*p)->fSampler.get());
2518 *outSynthesizedSamplerId = *sampler;
2521 SkDEBUGFAIL(
"sampler missing from fSynthesizedSamplerMap");
2524 SpvId* entry = fVariableMap.find(var);
2525 SkASSERTF(entry,
"%s", arg.description().c_str());
2530 tmpValueId = this->writeExpression(arg,
out);
2531 tmpVar = this->nextId(
nullptr);
2538 if (tmpValueId !=
NA) {
2544void SPIRVCodeGenerator::copyBackTempVars(
const std::vector<TempVar>& tempVars, OutputStream&
out) {
2545 for (
const TempVar& tempVar : tempVars) {
2546 SpvId load = this->nextId(tempVar.type);
2547 this->writeInstruction(
SpvOpLoad, this->getType(*tempVar.type),
load, tempVar.spvId,
out);
2548 tempVar.lvalue->store(
load,
out);
2552SpvId SPIRVCodeGenerator::writeFunctionCall(
const FunctionCall& c, OutputStream&
out) {
2553 const FunctionDeclaration&
function = c.function();
2555 return this->writeIntrinsicCall(c,
out);
2557 const ExpressionArray& arguments = c.arguments();
2561 "' is not defined");
2565 std::vector<TempVar> tempVars;
2568 for (
int i = 0;
i < arguments.size();
i++) {
2570 argumentIds.
push_back(this->writeFunctionCallArgument(c,
i, &tempVars,
out, &samplerId));
2571 if (samplerId !=
NA) {
2577 this->writeWord(this->getType(c.type()),
out);
2579 this->writeWord(*entry,
out);
2580 for (
SpvId id : argumentIds) {
2581 this->writeWord(
id,
out);
2584 this->copyBackTempVars(tempVars,
out);
2588SpvId SPIRVCodeGenerator::castScalarToType(
SpvId inputExprId,
2589 const Type& inputType,
2590 const Type& outputType,
2591 OutputStream&
out) {
2592 if (outputType.isFloat()) {
2593 return this->castScalarToFloat(inputExprId, inputType, outputType,
out);
2595 if (outputType.isSigned()) {
2596 return this->castScalarToSignedInt(inputExprId, inputType, outputType,
out);
2598 if (outputType.isUnsigned()) {
2599 return this->castScalarToUnsignedInt(inputExprId, inputType, outputType,
out);
2601 if (outputType.isBoolean()) {
2602 return this->castScalarToBoolean(inputExprId, inputType, outputType,
out);
2606 outputType.description());
2610SpvId SPIRVCodeGenerator::castScalarToFloat(
SpvId inputId,
const Type& inputType,
2611 const Type& outputType, OutputStream&
out) {
2613 if (inputType.isFloat()) {
2619 if (inputType.isBoolean()) {
2624 inputId, oneID, zeroID,
out);
2625 }
else if (inputType.isSigned()) {
2627 }
else if (inputType.isUnsigned()) {
2630 SkDEBUGFAILF(
"unsupported type for float typecast: %s", inputType.description().c_str());
2636SpvId SPIRVCodeGenerator::castScalarToSignedInt(
SpvId inputId,
const Type& inputType,
2637 const Type& outputType, OutputStream&
out) {
2639 if (inputType.isSigned()) {
2645 if (inputType.isBoolean()) {
2650 inputId, oneID, zeroID,
out);
2651 }
else if (inputType.isFloat()) {
2653 }
else if (inputType.isUnsigned()) {
2656 SkDEBUGFAILF(
"unsupported type for signed int typecast: %s",
2657 inputType.description().c_str());
2663SpvId SPIRVCodeGenerator::castScalarToUnsignedInt(
SpvId inputId,
const Type& inputType,
2664 const Type& outputType, OutputStream&
out) {
2666 if (inputType.isUnsigned()) {
2672 if (inputType.isBoolean()) {
2677 inputId, oneID, zeroID,
out);
2678 }
else if (inputType.isFloat()) {
2680 }
else if (inputType.isSigned()) {
2683 SkDEBUGFAILF(
"unsupported type for unsigned int typecast: %s",
2684 inputType.description().c_str());
2690SpvId SPIRVCodeGenerator::castScalarToBoolean(
SpvId inputId,
const Type& inputType,
2691 const Type& outputType, OutputStream&
out) {
2693 if (inputType.isBoolean()) {
2699 if (inputType.isSigned()) {
2703 inputId, zeroID,
out);
2704 }
else if (inputType.isUnsigned()) {
2708 inputId, zeroID,
out);
2709 }
else if (inputType.isFloat()) {
2713 inputId, zeroID,
out);
2715 SkDEBUGFAILF(
"unsupported type for boolean typecast: %s", inputType.description().c_str());
2722 OutputStream&
out) {
2725 SkASSERT(srcType.componentType().matches(dstType.componentType()));
2726 const Type& srcColumnType = srcType.componentType().toCompound(
fContext, srcType.rows(), 1);
2727 const Type& dstColumnType = dstType.componentType().toCompound(
fContext, dstType.rows(), 1);
2728 SkASSERT(dstType.componentType().isFloat());
2729 SpvId dstColumnTypeId = this->getType(dstColumnType);
2730 const SpvId zeroId = this->writeLiteral(0.0, dstType.componentType());
2731 const SpvId oneId = this->writeLiteral(1.0, dstType.componentType());
2734 for (
int i = 0;
i < dstType.columns();
i++) {
2735 if (
i < srcType.columns()) {
2737 SpvId srcColumn = this->writeOpCompositeExtract(srcColumnType,
src,
i,
out);
2739 if (srcType.rows() == dstType.rows()) {
2741 dstColumn = srcColumn;
2743 else if (dstType.rows() > srcType.rows()) {
2746 values.push_back(srcColumn);
2747 for (
int j = srcType.rows(); j < dstType.rows(); ++j) {
2748 values.push_back((
i == j) ? oneId : zeroId);
2750 dstColumn = this->writeOpCompositeConstruct(dstColumnType,
values,
out);
2754 dstColumn = this->nextId(&dstType);
2756 this->writeWord(dstColumnTypeId,
out);
2757 this->writeWord(dstColumn,
out);
2758 this->writeWord(srcColumn,
out);
2759 this->writeWord(srcColumn,
out);
2760 for (
int j = 0; j < dstType.rows(); j++) {
2761 this->writeWord(j,
out);
2768 for (
int j = 0; j < dstType.rows(); ++j) {
2769 values.push_back((
i == j) ? oneId : zeroId);
2775 return this->writeOpCompositeConstruct(dstType, columns,
out);
2778void SPIRVCodeGenerator::addColumnEntry(
const Type& columnType,
2783 OutputStream&
out) {
2786 if (currentColumn->
size() == rows) {
2788 SpvId columnId = this->writeOpCompositeConstruct(columnType, *currentColumn,
out);
2790 currentColumn->
clear();
2794SpvId SPIRVCodeGenerator::writeMatrixConstructor(
const ConstructorCompound& c, OutputStream&
out) {
2798 const Type& arg0Type = c.arguments()[0]->type();
2802 for (
const std::unique_ptr<Expression>& arg : c.arguments()) {
2806 if (arguments.
size() == 1 && arg0Type.isVector()) {
2811 for (
int i = 0;
i < 4; ++
i) {
2812 v[
i] = this->writeOpCompositeExtract(
type.componentType(), arguments[0],
i,
out);
2815 SpvId v0v1 = this->writeOpCompositeConstruct(vecType, {v[0], v[1]},
out);
2816 SpvId v2v3 = this->writeOpCompositeConstruct(vecType, {v[2], v[3]},
out);
2817 return this->writeOpCompositeConstruct(
type, {v0v1, v2v3},
out);
2820 int rows =
type.rows();
2826 for (
int i = 0;
i < arguments.
size();
i++) {
2827 const Type& argType = c.arguments()[
i]->type();
2828 if (currentColumn.
empty() && argType.isVector() && argType.columns() == rows) {
2831 }
else if (argType.columns() == 1) {
2833 this->addColumnEntry(columnType, ¤tColumn, &columnIds, rows, arguments[
i],
out);
2836 for (
int j = 0; j < argType.columns(); ++j) {
2837 SpvId swizzle = this->writeOpCompositeExtract(argType.componentType(),
2838 arguments[
i], j,
out);
2839 this->addColumnEntry(columnType, ¤tColumn, &columnIds, rows, swizzle,
out);
2844 return this->writeOpCompositeConstruct(
type, columnIds,
out);
2847SpvId SPIRVCodeGenerator::writeConstructorCompound(
const ConstructorCompound& c,
2848 OutputStream&
out) {
2849 return c.type().isMatrix() ? this->writeMatrixConstructor(c,
out)
2850 : this->writeVectorConstructor(c,
out);
2853SpvId SPIRVCodeGenerator::writeVectorConstructor(
const ConstructorCompound& c, OutputStream&
out) {
2855 const Type& componentType =
type.componentType();
2859 for (
int i = 0;
i < c.arguments().
size();
i++) {
2860 const Type& argType = c.arguments()[
i]->type();
2861 SkASSERT(componentType.numberKind() == argType.componentType().numberKind());
2863 SpvId arg = this->writeExpression(*c.arguments()[
i],
out);
2864 if (argType.isMatrix()) {
2869 for (
int j = 0; j < 4; ++j) {
2870 arguments.
push_back(this->writeOpCompositeExtract(componentType, arg,
2871 j / 2, j % 2,
out));
2873 }
else if (argType.isVector()) {
2877 for (
int j = 0; j < argType.columns(); j++) {
2878 arguments.
push_back(this->writeOpCompositeExtract(componentType, arg, j,
out));
2885 return this->writeOpCompositeConstruct(
type, arguments,
out);
2888SpvId SPIRVCodeGenerator::writeConstructorSplat(
const ConstructorSplat& c, OutputStream&
out) {
2890 SpvId argument = this->writeExpression(*c.argument(),
out);
2891 return this->splat(c.type(), argument,
out);
2894SpvId SPIRVCodeGenerator::writeCompositeConstructor(
const AnyConstructor& c, OutputStream&
out) {
2895 SkASSERT(c.type().isArray() || c.type().isStruct());
2896 auto ctorArgs = c.argumentSpan();
2899 for (
const std::unique_ptr<Expression>& arg : ctorArgs) {
2903 return this->writeOpCompositeConstruct(c.type(), arguments,
out);
2906SpvId SPIRVCodeGenerator::writeConstructorScalarCast(
const ConstructorScalarCast& c,
2907 OutputStream&
out) {
2909 if (
type.componentType().numberKind() == c.argument()->type().componentType().numberKind()) {
2910 return this->writeExpression(*c.argument(),
out);
2913 const Expression& ctorExpr = *c.argument();
2914 SpvId expressionId = this->writeExpression(ctorExpr,
out);
2915 return this->castScalarToType(expressionId, ctorExpr.type(),
type,
out);
2918SpvId SPIRVCodeGenerator::writeConstructorCompoundCast(
const ConstructorCompoundCast& c,
2919 OutputStream&
out) {
2920 const Type& ctorType = c.type();
2921 const Type& argType = c.argument()->type();
2922 SkASSERT(ctorType.isVector() || ctorType.isMatrix());
2925 SpvId compositeId = this->writeExpression(*c.argument(),
out);
2926 if (ctorType.componentType().numberKind() == argType.componentType().numberKind()) {
2931 if (ctorType.isMatrix()) {
2932 return this->writeMatrixCopy(compositeId, argType, ctorType,
out);
2937 const Type& srcType = argType.componentType();
2938 const Type& dstType = ctorType.componentType();
2941 for (
int index = 0; index < argType.columns(); ++index) {
2942 SpvId componentId = this->writeOpCompositeExtract(srcType, compositeId, index,
out);
2943 arguments.
push_back(this->castScalarToType(componentId, srcType, dstType,
out));
2946 return this->writeOpCompositeConstruct(ctorType, arguments,
out);
2949SpvId SPIRVCodeGenerator::writeConstructorDiagonalMatrix(
const ConstructorDiagonalMatrix& c,
2950 OutputStream&
out) {
2953 SkASSERT(c.argument()->type().isScalar());
2956 SpvId diagonal = this->writeExpression(*c.argument(),
out);
2965 for (
int column = 0; column <
type.columns(); column++) {
2966 for (
int row = 0; row <
type.rows(); row++) {
2967 arguments[row] = (row == column) ? diagonal : zeroId;
2969 columnIds.
push_back(this->writeOpCompositeConstruct(vecType, arguments,
out));
2971 return this->writeOpCompositeConstruct(
type, columnIds,
out);
2974SpvId SPIRVCodeGenerator::writeConstructorMatrixResize(
const ConstructorMatrixResize& c,
2975 OutputStream&
out) {
2977 SpvId argument = this->writeExpression(*c.argument(),
out);
2980 return this->writeMatrixCopy(argument, c.argument()->type(), c.type(),
out);
3003 if (
flags.isUniform()) {
3009 if (
flags.isBuffer()) {
3018 if (
flags.isWorkgroup()) {
3021 return fallbackStorageClass;
3025 switch (expr.
kind()) {
3026 case Expression::Kind::kVariableReference: {
3033 case Expression::Kind::kFieldAccess:
3042TArray<SpvId> SPIRVCodeGenerator::getAccessChain(
const Expression& expr, OutputStream&
out) {
3043 switch (expr.kind()) {
3045 const IndexExpression& indexExpr = expr.as<IndexExpression>();
3046 if (indexExpr.base()->is<Swizzle>()) {
3054 chain.
push_back(this->writeExpression(*indexExpr.index(),
out));
3057 case Expression::Kind::kFieldAccess: {
3058 const FieldAccess& fieldExpr = expr.as<FieldAccess>();
3064 SpvId id = this->getLValue(expr,
out)->getPointer();
3078 , fIsMemoryObject(isMemoryObject)
3080 , fPrecision(precision)
3088 return fIsMemoryObject;
3092 return fStorageClass;
3096 return fGen.writeOpLoad(fType, fPrecision, fPointer,
out);
3100 if (!fIsMemoryObject) {
3106 fGen.fStoreCache.
reset();
3109 fGen.writeOpStore(fStorageClass, fPointer,
value,
out);
3114 const SpvId fPointer;
3115 const bool fIsMemoryObject;
3117 const SPIRVCodeGenerator::Precision fPrecision;
3126 , fVecPointer(vecPointer)
3127 , fComponents(components)
3128 , fBaseType(&baseType)
3129 , fSwizzleType(&swizzleType)
3134 for (int8_t component : components) {
3135 if (component < 0 || component >= fComponents.
size()) {
3136 SkDEBUGFAILF(
"swizzle accessed nonexistent component %d", (
int)component);
3139 updatedSwizzle.
push_back(fComponents[component]);
3141 fComponents = updatedSwizzle;
3142 fSwizzleType = &newType;
3147 return fStorageClass;
3152 fGen.writeInstruction(
SpvOpLoad, fGen.getType(*fBaseType),
base, fVecPointer,
out);
3155 fGen.writeWord(fGen.getType(*fSwizzleType),
out);
3159 for (
int component : fComponents) {
3160 fGen.writeWord(component,
out);
3177 fGen.writeInstruction(
SpvOpLoad, fGen.getType(*fBaseType),
base, fVecPointer,
out);
3180 fGen.writeWord(fGen.getType(*fBaseType),
out);
3184 for (
int i = 0;
i < fBaseType->
columns();
i++) {
3189 for (
int j = 0; j < fComponents.
size(); j++) {
3190 if (fComponents[j] ==
i) {
3200 fGen.writeOpStore(fStorageClass, fVecPointer,
shuffle,
out);
3205 const SpvId fVecPointer;
3207 const Type* fBaseType;
3208 const Type* fSwizzleType;
3212int SPIRVCodeGenerator::findUniformFieldIndex(
const Variable& var)
const {
3213 int* fieldIndex = fTopLevelUniformMap.find(&var);
3214 return fieldIndex ? *fieldIndex : -1;
3217std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(
const Expression& expr,
3218 OutputStream&
out) {
3220 Precision precision =
type.highPrecision() ? Precision::kDefault : Precision::kRelaxed;
3221 switch (expr.kind()) {
3222 case Expression::Kind::kVariableReference: {
3223 const Variable& var = *expr.as<VariableReference>().variable();
3224 int uniformIdx = this->findUniformFieldIndex(var);
3225 if (uniformIdx >= 0) {
3227 SpvId memberId = this->nextId(
nullptr);
3230 this->writeInstruction(
SpvOpAccessChain, typeId, memberId, fUniformBufferId,
3232 return std::make_unique<PointerLValue>(
3241 SpvId* entry = fVariableMap.find(&var);
3242 SkASSERTF(entry,
"%s", expr.description().c_str());
3253 SpvId accessId = this->nextId(
nullptr);
3254 SpvId typeId = this->getPointerType(
type, storageClass);
3257 return std::make_unique<PointerLValue>(*
this,
3260 this->getType(
type),
3265 SpvId typeId = this->getType(
type, var.layout(), this->memoryLayoutForVariable(var));
3266 return std::make_unique<PointerLValue>(*
this, *entry,
3271 case Expression::Kind::kFieldAccess: {
3273 SpvId member = this->nextId(
nullptr);
3276 this->writeWord(this->getPointerType(
type, storageClass),
out);
3277 this->writeWord(member,
out);
3278 for (
SpvId idx : chain) {
3279 this->writeWord(idx,
out);
3281 return std::make_unique<PointerLValue>(
3287 this->memoryLayoutForStorageClass(storageClass)),
3291 case Expression::Kind::kSwizzle: {
3292 const Swizzle& swizzle = expr.as<Swizzle>();
3293 std::unique_ptr<LValue> lvalue = this->getLValue(*swizzle.base(),
out);
3294 if (lvalue->applySwizzle(swizzle.components(),
type)) {
3300 "unable to retrieve lvalue from swizzle");
3303 if (swizzle.components().size() == 1) {
3304 SpvId member = this->nextId(
nullptr);
3305 SpvId typeId = this->getPointerType(
type, storageClass);
3308 return std::make_unique<PointerLValue>(*
this, member,
3310 this->getType(
type),
3311 precision, storageClass);
3313 return std::make_unique<SwizzleLValue>(*
this,
base, swizzle.components(),
3314 swizzle.base()->type(),
type, storageClass);
3332 return std::make_unique<PointerLValue>(*
this,
result,
true,
3333 this->getType(
type), precision,
3339std::unique_ptr<Expression> SPIRVCodeGenerator::identifier(std::string_view
name) {
3340 std::unique_ptr<Expression> expr =
3342 return expr ? std::move(expr)
3346SpvId SPIRVCodeGenerator::writeVariableReference(
const VariableReference& ref, OutputStream&
out) {
3347 const Variable* variable = ref.variable();
3348 switch (variable->layout().fBuiltin) {
3353 return this->getLValue(*this->identifier(
"sk_FragCoord"),
out)->load(
out);
3359 return this->getLValue(*this->identifier(
"sk_Clockwise"),
out)->load(
out);
3365 "sk_SecondaryFragColor is not allowed in SPIR-V");
3370 return this->getLValue(*this->identifier(
"sk_FragCoord"),
out)->load(
out);
3374 this->addRTFlipUniform(ref.fPosition);
3379 static constexpr char DEVICE_COORDS_NAME[] =
"$device_FragCoords";
3395 std::unique_ptr<Expression> deviceCoord = this->identifier(DEVICE_COORDS_NAME);
3404 SpvId flippedY = this->writeBinaryExpression(
3410 flippedY = this->writeBinaryExpression(
3417 {deviceCoordX, flippedY, deviceCoordZW},
3422 return this->getLValue(*this->identifier(
"sk_Clockwise"),
out)->load(
out);
3426 this->addRTFlipUniform(ref.fPosition);
3430 static constexpr char DEVICE_CLOCKWISE_NAME[] =
"$device_Clockwise";
3440 DEVICE_CLOCKWISE_NAME,
3453 SpvId positiveRTFlip = this->writeBinaryExpression(
3459 std::unique_ptr<Expression> deviceClockwise = this->identifier(DEVICE_CLOCKWISE_NAME);
3460 SpvId deviceClockwiseID = this->writeExpression(*deviceClockwise,
out);
3461 return this->writeBinaryExpression(
3469 return this->writeExpression(*expr,
out);
3478 if (fUseTextureSamplerPairs && variable->type().isSampler()) {
3479 if (
const auto*
p = fSynthesizedSamplerMap.find(variable)) {
3480 SpvId* imgPtr = fVariableMap.find((*p)->fTexture.get());
3481 SpvId* samplerPtr = fVariableMap.find((*p)->fSampler.get());
3485 SpvId img = this->writeOpLoad(this->getType((*p)->fTexture->type()),
3486 Precision::kDefault, *imgPtr,
out);
3487 SpvId sampler = this->writeOpLoad(this->getType((*p)->fSampler->type()),
3488 Precision::kDefault,
3493 this->getType(variable->type()),
3500 SkDEBUGFAIL(
"sampler missing from fSynthesizedSamplerMap");
3502 return this->getLValue(ref,
out)->load(
out);
3507SpvId SPIRVCodeGenerator::writeIndexExpression(
const IndexExpression& expr, OutputStream&
out) {
3508 if (expr.base()->type().isVector()) {
3510 SpvId index = this->writeExpression(*expr.index(),
out);
3516 return getLValue(expr,
out)->load(
out);
3519SpvId SPIRVCodeGenerator::writeFieldAccess(
const FieldAccess&
f, OutputStream&
out) {
3520 return getLValue(
f,
out)->load(
out);
3523SpvId SPIRVCodeGenerator::writeSwizzle(
const Expression& baseExpr,
3525 OutputStream&
out) {
3526 size_t count = components.size();
3530 return this->writeOpCompositeExtract(
type,
base, components[0],
out);
3535 this->writeWord(this->getType(
type),
out);
3539 for (
int component : components) {
3540 this->writeWord(component,
out);
3545SpvId SPIRVCodeGenerator::writeSwizzle(
const Swizzle& swizzle, OutputStream&
out) {
3546 return this->writeSwizzle(*swizzle.base(), swizzle.components(),
out);
3549SpvId SPIRVCodeGenerator::writeBinaryOperation(
const Type& resultType,
const Type& operandType,
3551 bool writeComponentwiseIfMatrix,
3557 "unsupported operand for binary expression: " + operandType.description());
3560 if (writeComponentwiseIfMatrix && operandType.isMatrix()) {
3561 return this->writeComponentwiseMatrixBinary(resultType, lhs, rhs, op,
out);
3564 this->writeInstruction(op, this->getType(resultType),
result, lhs, rhs,
out);
3568SpvId SPIRVCodeGenerator::writeBinaryOperationComponentwiseIfMatrix(
const Type& resultType,
3569 const Type& operandType,
3573 OutputStream&
out) {
3574 return this->writeBinaryOperation(resultType, operandType, lhs, rhs,
3576 ifFloat, ifInt, ifUInt, ifBool,
out);
3579SpvId SPIRVCodeGenerator::writeBinaryOperation(
const Type& resultType,
const Type& operandType,
3582 return this->writeBinaryOperation(resultType, operandType, lhs, rhs,
3584 ifFloat, ifInt, ifUInt, ifBool,
out);
3588 OutputStream&
out) {
3589 if (operandType.isVector()) {
3597SpvId SPIRVCodeGenerator::writeMatrixComparison(
const Type& operandType,
SpvId lhs,
SpvId rhs,
3600 OutputStream&
out) {
3601 SpvOp_ compareOp =
is_float(operandType) ? floatOperator : intOperator;
3603 const Type& columnType = operandType.componentType().toCompound(
fContext,
3611 for (
int i = 0;
i < operandType.columns();
i++) {
3612 SpvId columnL = this->writeOpCompositeExtract(columnType, lhs,
i,
out);
3613 SpvId columnR = this->writeOpCompositeExtract(columnType, rhs,
i,
out);
3615 this->writeInstruction(compareOp, bvecType,
compare, columnL, columnR,
out);
3617 this->writeInstruction(vectorMergeOperator, boolType,
merge,
compare,
out);
3629SpvId SPIRVCodeGenerator::writeComponentwiseMatrixUnary(
const Type& operandType,
3632 OutputStream&
out) {
3634 const Type& columnType = operandType.columnType(
fContext);
3635 SpvId columnTypeId = this->getType(columnType);
3638 for (
int i = 0;
i < operandType.columns();
i++) {
3639 SpvId srcColumn = this->writeOpCompositeExtract(columnType, operand,
i,
out);
3640 SpvId dstColumn = this->nextId(&operandType);
3641 this->writeInstruction(op, columnTypeId, dstColumn, srcColumn,
out);
3645 return this->writeOpCompositeConstruct(operandType, columns,
out);
3648SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(
const Type& operandType,
SpvId lhs,
3651 const Type& columnType = operandType.columnType(
fContext);
3652 SpvId columnTypeId = this->getType(columnType);
3655 for (
int i = 0;
i < operandType.columns();
i++) {
3656 SpvId columnL = this->writeOpCompositeExtract(columnType, lhs,
i,
out);
3657 SpvId columnR = this->writeOpCompositeExtract(columnType, rhs,
i,
out);
3658 columns.
push_back(this->nextId(&operandType));
3659 this->writeInstruction(op, columnTypeId, columns[
i], columnL, columnR,
out);
3661 return this->writeOpCompositeConstruct(operandType, columns,
out);
3666 SpvId one = this->writeLiteral(1.0,
type);
3673 if (
type.isScalar()) {
3677 bool isMatrix =
type.isMatrix();
3680 int vectorSize = (isMatrix ?
type.rows() :
type.columns());
3681 const Type& vectorType =
type.componentType().toCompound(
fContext, vectorSize, 1);
3684 values.push_back_n(vectorSize,
id);
3685 id = this->writeOpCompositeConstruct(vectorType,
values,
out);
3691 id = this->writeOpCompositeConstruct(
type, matArguments,
out);
3702 return (
a.typeKind() ==
b.typeKind()) &&
3703 (
a.isScalar() ||
a.isVector() ||
a.isMatrix()) &&
3704 (
a.columns() ==
b.columns() &&
a.rows() ==
b.rows()) &&
3705 a.componentType().numberKind() ==
b.componentType().numberKind();
3708SpvId SPIRVCodeGenerator::writeDecomposedMatrixVectorMultiply(
const Type& leftType,
3710 const Type& rightType,
3712 const Type& resultType,
3713 OutputStream&
out) {
3715 const Type& columnType = leftType.columnType(
fContext);
3716 const Type& scalarType = rightType.componentType();
3718 for (
int n = 0; n < leftType.rows(); ++n) {
3720 SpvId matN = this->writeOpCompositeExtract(columnType, lhs, n,
out);
3723 SpvId vecN = this->writeOpCompositeExtract(scalarType, rhs, n,
out);
3735 columnType, product,
3743SpvId SPIRVCodeGenerator::writeBinaryExpression(
const Type& leftType,
SpvId lhs, Operator op,
3745 const Type& resultType, OutputStream&
out) {
3751 const Type* operandType;
3753 operandType = &leftType;
3757 if (leftType.isVector() && rightType.isNumber()) {
3758 if (resultType.componentType().isFloat()) {
3759 switch (op.kind()) {
3760 case Operator::Kind::SLASH: {
3761 rhs = this->writeReciprocal(rightType, rhs,
out);
3764 case Operator::Kind::STAR: {
3777 rhs = this->writeOpCompositeConstruct(leftType, arguments,
out);
3778 operandType = &leftType;
3779 }
else if (rightType.isVector() && leftType.isNumber()) {
3780 if (resultType.componentType().isFloat()) {
3781 if (op.kind() == Operator::Kind::STAR) {
3791 lhs = this->writeOpCompositeConstruct(rightType, arguments,
out);
3792 operandType = &rightType;
3793 }
else if (leftType.isMatrix()) {
3794 if (op.kind() == Operator::Kind::STAR) {
3798 rightType.isVector() &&
3799 !resultType.highPrecision()) {
3800 return this->writeDecomposedMatrixVectorMultiply(leftType, lhs, rightType, rhs,
3806 if (rightType.isMatrix()) {
3808 }
else if (rightType.isVector()) {
3815 this->writeInstruction(spvop, this->getType(resultType),
result, lhs, rhs,
out);
3823 SpvId rhsMatrix = this->splat(leftType, rhs,
out);
3826 return this->writeBinaryExpression(leftType, lhs, op, leftType, rhsMatrix,
3829 }
else if (rightType.isMatrix()) {
3830 if (op.kind() == Operator::Kind::STAR) {
3833 if (leftType.isVector()) {
3848 SpvId lhsMatrix = this->splat(rightType, lhs,
out);
3851 return this->writeBinaryExpression(rightType, lhsMatrix, op, rightType, rhs,
3860 switch (op.kind()) {
3861 case Operator::Kind::EQEQ: {
3862 if (operandType->isMatrix()) {
3863 return this->writeMatrixComparison(*operandType, lhs, rhs,
SpvOpFOrdEqual,
3866 if (operandType->isStruct()) {
3867 return this->writeStructComparison(*operandType, lhs, op, rhs,
out);
3869 if (operandType->isArray()) {
3870 return this->writeArrayComparison(*operandType, lhs, op, rhs,
out);
3873 const Type* tmpType;
3874 if (operandType->isVector()) {
3876 operandType->columns(),
3877 operandType->rows());
3879 tmpType = &resultType;
3885 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
3890 case Operator::Kind::NEQ:
3891 if (operandType->isMatrix()) {
3895 if (operandType->isStruct()) {
3896 return this->writeStructComparison(*operandType, lhs, op, rhs,
out);
3898 if (operandType->isArray()) {
3899 return this->writeArrayComparison(*operandType, lhs, op, rhs,
out);
3902 case Operator::Kind::LOGICALXOR:
3904 const Type* tmpType;
3905 if (operandType->isVector()) {
3907 operandType->columns(),
3908 operandType->rows());
3910 tmpType = &resultType;
3916 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
3923 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
3928 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpFOrdLessThan,
3930 case Operator::Kind::GTEQ:
3932 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
3935 case Operator::Kind::LTEQ:
3937 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
3941 return this->writeBinaryOperationComponentwiseIfMatrix(resultType, *operandType,
3944 case Operator::Kind::MINUS:
3945 return this->writeBinaryOperationComponentwiseIfMatrix(resultType, *operandType,
3948 case Operator::Kind::STAR:
3949 if (leftType.isMatrix() && rightType.isMatrix()) {
3956 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpFMul,
3958 case Operator::Kind::SLASH:
3959 return this->writeBinaryOperationComponentwiseIfMatrix(resultType, *operandType,
3962 case Operator::Kind::PERCENT:
3963 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpFMod,
3965 case Operator::Kind::SHL:
3966 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpUndef,
3969 case Operator::Kind::SHR:
3970 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpUndef,
3973 case Operator::Kind::BITWISEAND:
3974 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpUndef,
3976 case Operator::Kind::BITWISEOR:
3977 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpUndef,
3979 case Operator::Kind::BITWISEXOR:
3980 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpUndef,
3988SpvId SPIRVCodeGenerator::writeArrayComparison(
const Type& arrayType,
SpvId lhs, Operator op,
3991 SkASSERT(op.kind() == Operator::Kind::EQEQ || op.kind() == Operator::Kind::NEQ);
3993 const Type& componentType = arrayType.componentType();
3994 const int arraySize = arrayType.columns();
4000 for (
int index = 0; index < arraySize; ++index) {
4002 SpvId itemL = this->writeOpCompositeExtract(componentType, lhs, index,
out);
4003 SpvId itemR = this->writeOpCompositeExtract(componentType, rhs, index,
out);
4005 SpvId comparison = this->writeBinaryExpression(componentType, itemL, op,
4006 componentType, itemR, boolType,
out);
4008 allComparisons = this->mergeComparisons(comparison, allComparisons, op,
out);
4010 return allComparisons;
4013SpvId SPIRVCodeGenerator::writeStructComparison(
const Type& structType,
SpvId lhs, Operator op,
4016 SkASSERT(op.kind() == Operator::Kind::EQEQ || op.kind() == Operator::Kind::NEQ);
4024 for (
int index = 0; index < (
int)fields.
size(); ++index) {
4026 const Type& fieldType = *fields[index].fType;
4028 SpvId fieldL = this->writeOpCompositeExtract(fieldType, lhs, index,
out);
4029 SpvId fieldR = this->writeOpCompositeExtract(fieldType, rhs, index,
out);
4031 SpvId comparison = this->writeBinaryExpression(fieldType, fieldL, op, fieldType, fieldR,
4034 allComparisons = this->mergeComparisons(comparison, allComparisons, op,
out);
4036 return allComparisons;
4039SpvId SPIRVCodeGenerator::mergeComparisons(
SpvId comparison,
SpvId allComparisons, Operator op,
4040 OutputStream&
out) {
4042 if (allComparisons ==
NA) {
4047 SpvId boolTypeId = this->getType(boolType);
4048 SpvId logicalOp = this->nextId(&boolType);
4049 switch (op.kind()) {
4050 case Operator::Kind::EQEQ:
4052 comparison, allComparisons,
out);
4054 case Operator::Kind::NEQ:
4056 comparison, allComparisons,
out);
4059 SkDEBUGFAILF(
"mergeComparisons only supports == and !=, not %s", op.operatorName());
4065SpvId SPIRVCodeGenerator::writeBinaryExpression(
const BinaryExpression&
b, OutputStream&
out) {
4066 const Expression*
left =
b.left().get();
4067 const Expression*
right =
b.right().get();
4068 Operator op =
b.getOperator();
4070 switch (op.kind()) {
4073 SpvId rhs = this->writeExpression(*right,
out);
4074 this->getLValue(*left,
out)->store(rhs,
out);
4077 case Operator::Kind::LOGICALAND:
4079 return this->writeLogicalAnd(*
b.left(), *
b.right(),
out);
4081 case Operator::Kind::LOGICALOR:
4083 return this->writeLogicalOr(*
b.left(), *
b.right(),
out);
4089 std::unique_ptr<LValue> lvalue;
4091 if (op.isAssignment()) {
4092 lvalue = this->getLValue(*left,
out);
4093 lhs = lvalue->load(
out);
4096 lhs = this->writeExpression(*left,
out);
4099 SpvId rhs = this->writeExpression(*right,
out);
4100 SpvId result = this->writeBinaryExpression(
left->type(), lhs, op.removeAssignment(),
4108SpvId SPIRVCodeGenerator::writeLogicalAnd(
const Expression& left,
const Expression& right,
4109 OutputStream&
out) {
4111 SpvId lhs = this->writeExpression(left,
out);
4113 ConditionalOpCounts conditionalOps = this->getConditionalOpCounts();
4115 SpvId rhsLabel = this->nextId(
nullptr);
4117 SpvId lhsBlock = fCurrentBlock;
4120 this->writeLabel(rhsLabel, kBranchIsOnPreviousLine,
out);
4121 SpvId rhs = this->writeExpression(right,
out);
4122 SpvId rhsBlock = fCurrentBlock;
4124 this->writeLabel(end, kBranchIsAbove, conditionalOps,
out);
4127 lhsBlock, rhs, rhsBlock,
out);
4132SpvId SPIRVCodeGenerator::writeLogicalOr(
const Expression& left,
const Expression& right,
4133 OutputStream&
out) {
4135 SpvId lhs = this->writeExpression(left,
out);
4137 ConditionalOpCounts conditionalOps = this->getConditionalOpCounts();
4139 SpvId rhsLabel = this->nextId(
nullptr);
4141 SpvId lhsBlock = fCurrentBlock;
4144 this->writeLabel(rhsLabel, kBranchIsOnPreviousLine,
out);
4145 SpvId rhs = this->writeExpression(right,
out);
4146 SpvId rhsBlock = fCurrentBlock;
4148 this->writeLabel(end, kBranchIsAbove, conditionalOps,
out);
4151 lhsBlock, rhs, rhsBlock,
out);
4156SpvId SPIRVCodeGenerator::writeTernaryExpression(
const TernaryExpression& t, OutputStream&
out) {
4159 if (t.ifTrue()->type().columns() == 1 &&
4164 SpvId trueId = this->writeExpression(*t.ifTrue(),
out);
4165 SpvId falseId = this->writeExpression(*t.ifFalse(),
out);
4171 ConditionalOpCounts conditionalOps = this->getConditionalOpCounts();
4175 SpvId var = this->nextId(
nullptr);
4178 SpvId trueLabel = this->nextId(
nullptr);
4179 SpvId falseLabel = this->nextId(
nullptr);
4183 this->writeLabel(trueLabel, kBranchIsOnPreviousLine,
out);
4186 this->writeLabel(falseLabel, kBranchIsAbove, conditionalOps,
out);
4189 this->writeLabel(end, kBranchIsAbove, conditionalOps,
out);
4196SpvId SPIRVCodeGenerator::writePrefixExpression(
const PrefixExpression&
p, OutputStream&
out) {
4198 if (
p.getOperator().kind() == Operator::Kind::MINUS) {
4201 SpvId expr = this->writeExpression(*
p.operand(),
out);
4202 if (
type.isMatrix()) {
4203 return this->writeComponentwiseMatrixUnary(
type, expr, negateOp,
out);
4207 this->writeInstruction(negateOp, typeId,
result, expr,
out);
4210 switch (
p.getOperator().kind()) {
4212 return this->writeExpression(*
p.operand(),
out);
4214 case Operator::Kind::PLUSPLUS: {
4215 std::unique_ptr<LValue> lv = this->getLValue(*
p.operand(),
out);
4216 SpvId one = this->writeLiteral(1.0,
type.componentType());
4217 one = this->splat(
type, one,
out);
4226 case Operator::Kind::MINUSMINUS: {
4227 std::unique_ptr<LValue> lv = this->getLValue(*
p.operand(),
out);
4228 SpvId one = this->writeLiteral(1.0,
type.componentType());
4229 one = this->splat(
type, one,
out);
4238 case Operator::Kind::LOGICALNOT: {
4239 SkASSERT(
p.operand()->type().isBoolean());
4242 this->writeExpression(*
p.operand(),
out),
out);
4245 case Operator::Kind::BITWISENOT: {
4248 this->writeExpression(*
p.operand(),
out),
out);
4258SpvId SPIRVCodeGenerator::writePostfixExpression(
const PostfixExpression&
p, OutputStream&
out) {
4260 std::unique_ptr<LValue> lv = this->getLValue(*
p.operand(),
out);
4262 SpvId one = this->writeLiteral(1.0,
type.componentType());
4263 one = this->splat(
type, one,
out);
4264 switch (
p.getOperator().kind()) {
4265 case Operator::Kind::PLUSPLUS: {
4270 lv->store(temp,
out);
4273 case Operator::Kind::MINUSMINUS: {
4278 lv->store(temp,
out);
4288SpvId SPIRVCodeGenerator::writeLiteral(
const Literal& l) {
4289 return this->writeLiteral(l.value(), l.type());
4293 switch (
type.numberKind()) {
4295 float floatVal =
value;
4297 memcpy(&valueBits, &floatVal,
sizeof(valueBits));
4298 return this->writeOpConstant(
type, valueBits);
4301 return value ? this->writeOpConstantTrue(
type)
4302 : this->writeOpConstantFalse(
type);
4310SpvId SPIRVCodeGenerator::writeFunctionStart(
const FunctionDeclaration&
f, OutputStream&
out) {
4312 SpvId returnTypeId = this->getType(
f.returnType());
4313 SpvId functionTypeId = this->getFunctionType(
f);
4316 std::string mangledName =
f.mangledName();
4319 std::string_view(mangledName.c_str(), mangledName.size()),
4321 for (
const Variable* parameter :
f.parameters()) {
4322 if (fUseTextureSamplerPairs && parameter->type().isSampler()) {
4323 auto [
texture, sampler] = this->synthesizeTextureAndSampler(*parameter);
4325 SpvId textureId = this->nextId(
nullptr);
4326 SpvId samplerId = this->nextId(
nullptr);
4327 fVariableMap.set(
texture, textureId);
4328 fVariableMap.set(sampler, samplerId);
4336 SpvId id = this->nextId(
nullptr);
4337 fVariableMap.set(parameter,
id);
4339 SpvId type = this->getFunctionParameterType(parameter->type(), parameter->layout());
4346SpvId SPIRVCodeGenerator::writeFunction(
const FunctionDefinition&
f, OutputStream&
out) {
4347 ConditionalOpCounts conditionalOps = this->getConditionalOpCounts();
4349 fVariableBuffer.
reset();
4352 this->writeLabel(this->nextId(
nullptr), kBranchlessBlock,
out);
4353 StringStream bodyBuffer;
4354 this->writeBlock(
f.body()->as<
Block>(), bodyBuffer);
4356 if (
f.declaration().isMain()) {
4360 if (fCurrentBlock) {
4361 if (
f.declaration().returnType().isVoid()) {
4368 this->pruneConditionalOps(conditionalOps);
4374 if (layout.fLocation >= 0) {
4378 if (layout.fBinding >= 0) {
4379 if (isPushConstant) {
4386 if (layout.fIndex >= 0) {
4390 if (layout.fSet >= 0) {
4391 if (isPushConstant) {
4398 if (layout.fInputAttachmentIndex >= 0) {
4400 layout.fInputAttachmentIndex, fDecorationBuffer);
4409void SPIRVCodeGenerator::writeFieldLayout(
const Layout& layout,
SpvId target,
int member) {
4413 if (layout.fLocation >= 0) {
4415 layout.fLocation, fDecorationBuffer);
4417 if (layout.fIndex >= 0) {
4419 layout.fIndex, fDecorationBuffer);
4421 if (layout.fInputAttachmentIndex >= 0) {
4423 layout.fInputAttachmentIndex, fDecorationBuffer);
4425 if (layout.fBuiltin >= 0) {
4427 layout.fBuiltin, fDecorationBuffer);
4431MemoryLayout SPIRVCodeGenerator::memoryLayoutForStorageClass(
SpvStorageClass_ storageClass) {
4433 : fDefaultMemoryLayout;
4436MemoryLayout SPIRVCodeGenerator::memoryLayoutForVariable(
const Variable& v)
const {
4439 : fDefaultMemoryLayout;
4442SpvId SPIRVCodeGenerator::writeInterfaceBlock(
const InterfaceBlock& intf,
bool appendRTFlip) {
4443 MemoryLayout memoryLayout = this->memoryLayoutForVariable(*intf.var());
4445 const Variable& intfVar = *intf.var();
4447 if (!memoryLayout.isSupported(
type)) {
4449 "' is not permitted here");
4450 return this->nextId(
nullptr);
4455 !fWroteRTFlip &&
type.isStruct()) {
4462 fields.emplace_back(Position(),
4484 intfVar.modifiersPosition(),
4486 intfVar.modifierFlags(),
4490 intfVar.isBuiltin(),
4491 intfVar.storage()));
4492 InterfaceBlock modifiedCopy(intf.fPosition, modifiedVar);
4493 result = this->writeInterfaceBlock(modifiedCopy,
false);
4495 Position(), modifiedVar, rtFlipStructType->fields().size() - 1));
4497 fVariableMap.set(&intfVar,
result);
4498 fWroteRTFlip =
true;
4502 if (intfVar.layout().fBuiltin == -1) {
4509 bool isStorageBuffer = intfVar.modifierFlags().isBuffer();
4515 SpvId ptrType = this->nextId(
nullptr);
4516 this->writeInstruction(
SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
4518 Layout layout = intfVar.layout();
4522 this->writeLayout(layout,
result, intfVar.fPosition);
4523 fVariableMap.set(&intfVar,
result);
4544bool SPIRVCodeGenerator::writeGlobalVarDeclaration(
ProgramKind kind,
4545 const VarDeclaration& varDecl) {
4546 const Variable* var = varDecl.var();
4550 if (backendFlags & ~kPermittedBackendFlags) {
4565 fTopLevelUniforms.push_back(&varDecl);
4569 if (fUseTextureSamplerPairs && var->type().isSampler()) {
4570 if (var->layout().fTexture == -1 || var->layout().fSampler == -1) {
4572 "and sampler indices");
4577 auto [
texture, sampler] = this->synthesizeTextureAndSampler(*var);
4578 this->writeGlobalVar(kind, storageClass, *
texture);
4579 this->writeGlobalVar(kind, storageClass, *sampler);
4584 SpvId id = this->writeGlobalVar(kind, storageClass, *var);
4585 if (
id !=
NA && varDecl.value()) {
4588 SpvId value = this->writeExpression(*varDecl.value(), fGlobalInitializersBuffer);
4589 this->writeOpStore(storageClass,
id,
value, fGlobalInitializersBuffer);
4597 const Variable& var) {
4598 Layout layout = var.layout();
4599 const ModifierFlags
flags = var.modifierFlags();
4601 switch (layout.fBuiltin) {
4620 fVariableMap.set(&var,
id);
4626 SpvId typeId = this->getPointerType(*
type,
4628 this->memoryLayoutForStorageClass(storageClass),
4630 this->writeInstruction(
SpvOpVariable, typeId,
id, storageClass, fConstantBuffer);
4631 this->writeInstruction(
SpvOpName,
id, var.name(), fNameBuffer);
4632 this->writeLayout(layout,
id, var.fPosition);
4640 if (
flags.isWriteOnly()) {
4642 }
else if (
flags.isReadOnly()) {
4649void SPIRVCodeGenerator::writeVarDeclaration(
const VarDeclaration& varDecl, OutputStream&
out) {
4656 const Variable* var = varDecl.var();
4657 SpvId id = this->nextId(&var->type());
4658 fVariableMap.set(var,
id);
4661 this->writeInstruction(
SpvOpName,
id, var->name(), fNameBuffer);
4662 if (varDecl.value()) {
4668void SPIRVCodeGenerator::writeStatement(
const Statement&
s, OutputStream&
out) {
4672 case Statement::Kind::kBlock:
4675 case Statement::Kind::kExpression:
4676 this->writeExpression(*
s.as<ExpressionStatement>().expression(),
out);
4678 case Statement::Kind::kReturn:
4679 this->writeReturnStatement(
s.as<ReturnStatement>(),
out);
4681 case Statement::Kind::kVarDeclaration:
4682 this->writeVarDeclaration(
s.as<VarDeclaration>(),
out);
4684 case Statement::Kind::kIf:
4685 this->writeIfStatement(
s.as<IfStatement>(),
out);
4687 case Statement::Kind::kFor:
4688 this->writeForStatement(
s.as<ForStatement>(),
out);
4690 case Statement::Kind::kDo:
4691 this->writeDoStatement(
s.as<DoStatement>(),
out);
4693 case Statement::Kind::kSwitch:
4694 this->writeSwitchStatement(
s.as<SwitchStatement>(),
out);
4696 case Statement::Kind::kBreak:
4706 SkDEBUGFAILF(
"unsupported statement: %s",
s.description().c_str());
4711void SPIRVCodeGenerator::writeBlock(
const Block&
b, OutputStream&
out) {
4712 for (
const std::unique_ptr<Statement>& stmt :
b.children()) {
4713 this->writeStatement(*stmt,
out);
4717SPIRVCodeGenerator::ConditionalOpCounts SPIRVCodeGenerator::getConditionalOpCounts() {
4718 return {fReachableOps.
size(), fStoreOps.
size()};
4721void SPIRVCodeGenerator::pruneConditionalOps(ConditionalOpCounts
ops) {
4723 while (fReachableOps.
size() >
ops.numReachableOps) {
4724 SpvId prunableSpvId = fReachableOps.
back();
4725 const Instruction* prunableOp = fSpvIdCache.
find(prunableSpvId);
4728 fOpCache.remove(*prunableOp);
4729 fSpvIdCache.
remove(prunableSpvId);
4731 SkDEBUGFAIL(
"reachable-op list contains unrecognized SpvId");
4738 while (fStoreOps.
size() >
ops.numStoreOps) {
4739 if (fStoreCache.
find(fStoreOps.
back())) {
4746void SPIRVCodeGenerator::writeIfStatement(
const IfStatement& stmt, OutputStream&
out) {
4748 SpvId ifTrue = this->nextId(
nullptr);
4749 SpvId ifFalse = this->nextId(
nullptr);
4751 ConditionalOpCounts conditionalOps = this->getConditionalOpCounts();
4753 if (stmt.ifFalse()) {
4757 this->writeLabel(ifTrue, kBranchIsOnPreviousLine,
out);
4758 this->writeStatement(*stmt.ifTrue(),
out);
4759 if (fCurrentBlock) {
4762 this->writeLabel(ifFalse, kBranchIsAbove, conditionalOps,
out);
4763 this->writeStatement(*stmt.ifFalse(),
out);
4764 if (fCurrentBlock) {
4767 this->writeLabel(end, kBranchIsAbove, conditionalOps,
out);
4771 this->writeLabel(ifTrue, kBranchIsOnPreviousLine,
out);
4772 this->writeStatement(*stmt.ifTrue(),
out);
4773 if (fCurrentBlock) {
4776 this->writeLabel(ifFalse, kBranchIsAbove, conditionalOps,
out);
4780void SPIRVCodeGenerator::writeForStatement(
const ForStatement&
f, OutputStream&
out) {
4781 if (
f.initializer()) {
4782 this->writeStatement(*
f.initializer(),
out);
4785 ConditionalOpCounts conditionalOps = this->getConditionalOpCounts();
4793 SpvId body = this->nextId(
nullptr);
4799 this->writeLabel(
header, kBranchIsBelow, conditionalOps,
out);
4802 this->writeLabel(start, kBranchIsOnPreviousLine,
out);
4809 this->writeLabel(body, kBranchIsOnPreviousLine,
out);
4810 this->writeStatement(*
f.statement(),
out);
4811 if (fCurrentBlock) {
4814 this->writeLabel(
next, kBranchIsAbove, conditionalOps,
out);
4816 this->writeExpression(*
f.next(),
out);
4819 this->writeLabel(end, kBranchIsAbove, conditionalOps,
out);
4824void SPIRVCodeGenerator::writeDoStatement(
const DoStatement&
d, OutputStream&
out) {
4825 ConditionalOpCounts conditionalOps = this->getConditionalOpCounts();
4834 SpvId continueTarget = this->nextId(
nullptr);
4835 fContinueTarget.
push_back(continueTarget);
4839 this->writeLabel(
header, kBranchIsBelow, conditionalOps,
out);
4842 this->writeLabel(start, kBranchIsOnPreviousLine,
out);
4843 this->writeStatement(*
d.statement(),
out);
4844 if (fCurrentBlock) {
4846 this->writeLabel(
next, kBranchIsOnPreviousLine,
out);
4849 this->writeLabel(continueTarget, kBranchIsAbove, conditionalOps,
out);
4852 this->writeLabel(end, kBranchIsAbove, conditionalOps,
out);
4857void SPIRVCodeGenerator::writeSwitchStatement(
const SwitchStatement&
s, OutputStream&
out) {
4860 ConditionalOpCounts conditionalOps = this->getConditionalOpCounts();
4872 for (
const std::unique_ptr<Statement>& stmt : cases) {
4873 const SwitchCase& c = stmt->as<SwitchCase>();
4874 SpvId label = this->nextId(
nullptr);
4876 if (!c.isDefault()) {
4879 defaultLabel = label;
4889 SkBitSet caseIsCollapsed(cases.size());
4890 for (
int index = cases.size() - 2; index >= 0; index--) {
4891 if (cases[index]->as<SwitchCase>().statement()->isEmpty()) {
4892 caseIsCollapsed.set(index);
4893 labels[index] = labels[index + 1];
4902 this->writeWord(defaultLabel,
out);
4903 for (
int i = 0;
i < cases.size(); ++
i) {
4904 const SwitchCase& c = cases[
i]->as<SwitchCase>();
4905 if (c.isDefault()) {
4908 this->writeWord(c.value(),
out);
4909 this->writeWord(labels[
i],
out);
4911 for (
int i = 0;
i < cases.size(); ++
i) {
4912 if (caseIsCollapsed.test(
i)) {
4915 const SwitchCase& c = cases[
i]->as<SwitchCase>();
4917 this->writeLabel(labels[
i], kBranchIsOnPreviousLine,
out);
4919 this->writeLabel(labels[
i], kBranchIsAbove, conditionalOps,
out);
4921 this->writeStatement(*c.statement(),
out);
4922 if (fCurrentBlock) {
4926 this->writeLabel(end, kBranchIsAbove, conditionalOps,
out);
4930void SPIRVCodeGenerator::writeReturnStatement(
const ReturnStatement& r, OutputStream&
out) {
4931 if (r.expression()) {
4944SPIRVCodeGenerator::EntrypointAdapter SPIRVCodeGenerator::writeEntrypointAdapter(
4945 const FunctionDeclaration&
main) {
4953 const Symbol* skFragColorSymbol = symbolTable->find(
"sk_FragColor");
4955 const Variable& skFragColorVar = skFragColorSymbol->as<Variable>();
4956 auto skFragColorRef = std::make_unique<VariableReference>(Position(), &skFragColorVar,
4959 if (!
main.returnType().matches(skFragColorRef->type())) {
4961 main.returnType().description() +
"' from main()");
4964 ExpressionArray
args;
4965 if (
main.parameters().size() == 1) {
4968 "SPIR-V does not support parameter of type '" +
4969 main.parameters()[0]->type().description() +
"' to main()");
4972 double kZero[2] = {0.0, 0.0};
4976 auto callMainFn = std::make_unique<FunctionCall>(Position(), &
main.returnType(), &
main,
4980 auto assignmentStmt = std::make_unique<ExpressionStatement>(std::make_unique<BinaryExpression>(
4982 std::move(skFragColorRef),
4984 std::move(callMainFn),
4985 &
main.returnType()));
4989 entrypointStmts.
push_back(std::move(assignmentStmt));
4990 auto entrypointBlock =
Block::Make(Position(), std::move(entrypointStmts),
4991 Block::Kind::kBracedScope,
nullptr);
4993 EntrypointAdapter adapter;
4994 adapter.entrypointDecl =
4995 std::make_unique<FunctionDeclaration>(
fContext,
5005 *adapter.entrypointDecl,
5006 std::move(entrypointBlock),
5009 adapter.entrypointDecl->setDefinition(adapter.entrypointDef.get());
5013void SPIRVCodeGenerator::writeUniformBuffer(SymbolTable* topLevelSymbolTable) {
5014 SkASSERT(!fTopLevelUniforms.empty());
5015 static constexpr char kUniformBufferName[] =
"_UniformBuffer";
5021 for (
const VarDeclaration* topLevelUniform : fTopLevelUniforms) {
5022 const Variable* var = topLevelUniform->var();
5023 fTopLevelUniformMap.set(var, (
int)fields.
size());
5025 fields.
emplace_back(var->fPosition, var->layout(),
flags, var->name(), &var->type());
5042 fUniformBuffer.fStruct.get(),
5049 fUniformBuffer.fInterfaceBlock =
5050 std::make_unique<InterfaceBlock>(Position(), fUniformBuffer.fInnerVariable.get());
5053 fUniformBufferId = this->writeInterfaceBlock(*fUniformBuffer.fInterfaceBlock);
5056void SPIRVCodeGenerator::addRTFlipUniform(Position
pos) {
5064 fWroteRTFlip =
true;
5081 std::string_view
name =
"sksl_synthetic_uniforms";
5084 bool usePushConstants =
fProgram.
fConfig->fSettings.fUsePushConstants;
5085 int binding = -1,
set = -1;
5086 if (!usePushConstants) {
5088 if (binding == -1) {
5117 std::make_unique<FieldSymbol>(Position(), intfVar, 0));
5119 InterfaceBlock intf(Position(), intfVar);
5120 this->writeInterfaceBlock(intf,
false);
5123std::tuple<const Variable*, const Variable*> SPIRVCodeGenerator::synthesizeTextureAndSampler(
5124 const Variable& combinedSampler) {
5128 auto data = std::make_unique<SynthesizedTextureSamplerPair>();
5130 Layout texLayout = combinedSampler.layout();
5131 texLayout.fBinding = texLayout.fTexture;
5132 data->fTextureName = std::string(combinedSampler.name()) +
"_texture";
5137 combinedSampler.modifierFlags(),
5138 &combinedSampler.type().textureType(),
5144 Layout samplerLayout = combinedSampler.layout();
5145 samplerLayout.fBinding = samplerLayout.fSampler;
5146 samplerLayout.fFlags &= ~LayoutFlag::kAllPixelFormats;
5147 data->fSamplerName = std::string(combinedSampler.name()) +
"_sampler";
5152 combinedSampler.modifierFlags(),
5159 const Variable* t =
texture.get();
5160 const Variable*
s = sampler.get();
5162 data->fSampler = std::move(sampler);
5163 fSynthesizedSamplerMap.set(&combinedSampler, std::move(
data));
5168void SPIRVCodeGenerator::writeInstructions(
const Program& program, OutputStream&
out) {
5169 fGLSLExtendedInstructions = this->nextId(
nullptr);
5173 const FunctionDeclaration*
main =
nullptr;
5174 int localSizeX = 1, localSizeY = 1, localSizeZ = 1;
5175 Position combinedSamplerPos;
5176 Position separateSamplerPos;
5177 for (
const ProgramElement*
e : program.elements()) {
5178 switch (
e->kind()) {
5181 const FunctionDefinition& funcDef =
e->as<FunctionDefinition>();
5182 const FunctionDeclaration& funcDecl = funcDef.declaration();
5183 fFunctionMap.set(&funcDecl, this->nextId(
nullptr));
5184 if (funcDecl.isMain()) {
5189 case ProgramElement::Kind::kGlobalVar: {
5193 const GlobalVarDeclaration& decl =
e->as<GlobalVarDeclaration>();
5194 const Variable& var = *decl.varDeclaration().var();
5195 if (var.type().isSampler()) {
5197 combinedSamplerPos = decl.position();
5200 separateSamplerPos = decl.position();
5205 case ProgramElement::Kind::kModifiers: {
5209 const ModifiersDeclaration& modifiers =
e->as<ModifiersDeclaration>();
5210 if (modifiers.layout().fLocalSizeX >= 0) {
5211 localSizeX = modifiers.layout().fLocalSizeX;
5213 if (modifiers.layout().fLocalSizeY >= 0) {
5214 localSizeY = modifiers.layout().fLocalSizeY;
5216 if (modifiers.layout().fLocalSizeZ >= 0) {
5217 localSizeZ = modifiers.layout().fLocalSizeZ;
5233 if (combinedSamplerPos.valid() && separateSamplerPos.valid()) {
5239 fUseTextureSamplerPairs = separateSamplerPos.valid();
5242 std::set<SpvId> interfaceVars;
5243 for (
const ProgramElement*
e : program.elements()) {
5244 if (
e->is<InterfaceBlock>()) {
5245 const InterfaceBlock& intf =
e->as<InterfaceBlock>();
5246 SpvId id = this->writeInterfaceBlock(intf);
5249 intf.var()->layout().fBuiltin == -1) {
5250 interfaceVars.insert(
id);
5258 const VarDeclaration* missingClockwiseDecl =
nullptr;
5260 if (
const Symbol* clockwise = program.fSymbols->findBuiltinSymbol(
"sk_Clockwise")) {
5261 missingClockwiseDecl = clockwise->as<Variable>().varDeclaration();
5265 for (
const ProgramElement*
e : program.elements()) {
5266 if (
e->is<GlobalVarDeclaration>()) {
5267 const VarDeclaration& decl =
e->as<GlobalVarDeclaration>().varDeclaration();
5268 if (!this->writeGlobalVarDeclaration(program.fConfig->fKind, decl)) {
5271 if (missingClockwiseDecl == &decl) {
5273 missingClockwiseDecl =
nullptr;
5279 if (missingClockwiseDecl) {
5280 if (!this->writeGlobalVarDeclaration(program.fConfig->fKind, *missingClockwiseDecl)) {
5283 missingClockwiseDecl =
nullptr;
5286 if (!fTopLevelUniforms.empty()) {
5291 EntrypointAdapter adapter;
5293 adapter = this->writeEntrypointAdapter(*
main);
5294 if (adapter.entrypointDecl) {
5295 fFunctionMap.set(adapter.entrypointDecl.get(), this->nextId(
nullptr));
5296 this->writeFunction(*adapter.entrypointDef, body);
5297 main = adapter.entrypointDecl.get();
5301 for (
const ProgramElement*
e : program.elements()) {
5302 if (
e->is<FunctionDefinition>()) {
5303 this->writeFunction(
e->as<FunctionDefinition>(), body);
5307 for (
const auto& [var, spvId] : fVariableMap) {
5310 interfaceVars.insert(spvId);
5313 this->writeCapabilities(
out);
5317 (
SpvId)(3 + (
main->name().length() + 4) / 4) + (int32_t)interfaceVars.size(),
5326 SK_ABORT(
"cannot write this kind of program to SPIR-V\n");
5329 this->writeWord(entryPoint,
out);
5330 this->writeString(
main->name(),
out);
5331 for (
int var : interfaceVars) {
5332 this->writeWord(var,
out);
5343 localSizeX, localSizeY, localSizeZ,
5346 for (
const ProgramElement*
e : program.elements()) {
5347 if (
e->is<Extension>()) {
5365 this->writeWord(fIdCount, *
fOut);
5366 this->writeWord(0, *
fOut);
5371#if defined(SK_ENABLE_SPIRV_VALIDATION)
5374 const uint32_t* programData =
reinterpret_cast<const uint32_t*
>(program.data());
5375 size_t programSize = program.size() / 4;
5377 spvtools::SpirvTools
tools(SPV_ENV_VULKAN_1_0);
5379 auto msgFn = [&
errors](spv_message_level_t,
const char*,
const spv_position_t&,
const char*
m) {
5380 errors +=
"SPIR-V validation error: ";
5384 tools.SetMessageConsumer(msgFn);
5389 bool result =
tools.Validate(programData, programSize);
5391#if defined(SKSL_STANDALONE)
5393 std::string disassembly;
5394 uint32_t
options = spvtools::SpirvTools::kDefaultDisassembleOption;
5395 options |= SPV_BINARY_TO_TEXT_OPTION_INDENT;
5396 if (
tools.Disassemble(programData, programSize, &disassembly,
options)) {
5397 errors.append(disassembly);
5413#ifdef SK_ENABLE_SPIRV_VALIDATION
5427 program.
fContext->fErrors->setSource(std::string_view());
static float next(float f)
static void merge(const uint8_t *SK_RESTRICT row, int rowN, const SkAlpha *SK_RESTRICT srcAA, const int16_t *SK_RESTRICT srcRuns, SkAlpha *SK_RESTRICT dstAA, int16_t *SK_RESTRICT dstRuns, int width)
#define SkDEBUGFAIL(message)
#define SK_ABORT(message,...)
#define SkDEBUGFAILF(fmt,...)
#define SkASSERTF(cond, fmt,...)
static uint32_t hash(const SkShaderBase::GradientInfo &v)
constexpr int SK_SAMPLEMASK_BUILTIN
constexpr int SK_CLOCKWISE_BUILTIN
constexpr int SK_FRAGCOLOR_BUILTIN
constexpr int SK_SECONDARYFRAGCOLOR_BUILTIN
constexpr int SK_FRAGCOORD_BUILTIN
constexpr int SK_SAMPLEMASKIN_BUILTIN
constexpr int DEVICE_CLOCKWISE_BUILTIN
constexpr int DEVICE_FRAGCOORDS_BUILTIN
static constexpr SkSL::Layout kDefaultTypeLayout
#define BY_TYPE_GLSL(ifFloat, ifInt, ifUInt)
SkSpan(Container &&) -> SkSpan< std::remove_pointer_t< decltype(std::data(std::declval< Container >()))> >
constexpr int SkToInt(S x)
static constexpr bool SkToBool(const T &x)
int main(int argc, char **argv)
static std::unique_ptr< Statement > Make(Position pos, StatementArray statements, Kind kind=Kind::kBracedScope, std::unique_ptr< SymbolTable > symbols=nullptr)
const std::unique_ptr< Type > fFloat2
const std::unique_ptr< Type > fHalf4
const std::unique_ptr< Type > fUInt2
const std::unique_ptr< Type > fInt2
const std::unique_ptr< Type > fInt
const std::unique_ptr< Type > fAtomicUInt
const std::unique_ptr< Type > fSampler
const std::unique_ptr< Type > fFloat4
const std::unique_ptr< Type > fUInt
const std::unique_ptr< Type > fBool
const std::unique_ptr< Type > fVoid
const std::unique_ptr< Type > fFloat
const std::unique_ptr< Type > fFloat3
static constexpr float kSharpenTexturesBias
CodeGenerator(const Context *context, const ShaderCaps *caps, const Program *program, OutputStream *stream)
static const Expression * GetConstantValueOrNull(const Expression &value)
static std::unique_ptr< Expression > MakeFromConstants(const Context &context, Position pos, const Type &type, const double values[])
const BuiltinTypes & fTypes
void error(Position position, std::string_view msg)
std::unique_ptr< Expression > & base()
const FunctionDefinition * definition() const
std::unique_ptr< Statement > & body()
static std::unique_ptr< FunctionDefinition > Convert(const Context &context, Position pos, const FunctionDeclaration &function, std::unique_ptr< Statement > body, bool builtin)
std::unique_ptr< Expression > & base()
static const Type & IndexType(const Context &context, const Type &type)
static std::unique_ptr< Literal > MakeInt(const Context &context, Position pos, SKSL_INT value)
static std::unique_ptr< Literal > MakeFloat(const Context &context, Position pos, float value)
SpvStorageClass storageClass() const override
SpvId load(OutputStream &out) override
void store(SpvId value, OutputStream &out) override
bool isMemoryObjectPointer() const override
SpvId getPointer() override
PointerLValue(SPIRVCodeGenerator &gen, SpvId pointer, bool isMemoryObject, SpvId type, SPIRVCodeGenerator::Precision precision, SpvStorageClass_ storageClass)
virtual SpvStorageClass storageClass() const =0
virtual SpvId load(OutputStream &out)=0
virtual SpvId getPointer()
virtual bool applySwizzle(const ComponentArray &components, const Type &newType)
virtual void store(SpvId value, OutputStream &out)=0
virtual bool isMemoryObjectPointer() const
bool generateCode() override
SPIRVCodeGenerator(const Context *context, const ShaderCaps *caps, const Program *program, OutputStream *out)
static constexpr SpvId NA
SpvId load(OutputStream &out) override
SwizzleLValue(SPIRVCodeGenerator &gen, SpvId vecPointer, const ComponentArray &components, const Type &baseType, const Type &swizzleType, SpvStorageClass_ storageClass)
SpvStorageClass storageClass() const override
void store(SpvId value, OutputStream &out) override
bool applySwizzle(const ComponentArray &components, const Type &newType) override
const Type * addArrayDimension(const Context &context, const Type *type, int arraySize)
T * takeOwnershipOfSymbol(std::unique_ptr< T > symbol)
const Type & type() const
virtual bool isVector() const
virtual int columns() const
virtual bool isScalar() const
static std::unique_ptr< Type > MakeStructType(const Context &context, Position pos, std::string_view name, skia_private::TArray< Field > fields, bool interfaceBlock=false)
TypeKind typeKind() const
std::unique_ptr< Expression > & value()
static std::unique_ptr< Variable > Make(Position pos, Position modifiersPosition, const Layout &layout, ModifierFlags flags, const Type *type, std::string_view name, std::string mangledName, bool builtin, Storage storage)
ModifierFlags modifierFlags() const
virtual const Layout & layout() const
constexpr T * data() const
constexpr bool empty() const
constexpr size_t size() const
void resize(size_t count)
void reserve_exact(int n)
T & emplace_back(Args &&... args)
V * find(const K &key) const
void remove(const K &key)
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
FlutterSemanticsFlag flags
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint32_t uint32_t * format
Dart_NativeFunction function
static uint32_t Mix(uint32_t hash)
uint32_t Hash32(const void *data, size_t bytes, uint32_t seed)
SK_API sk_sp< SkDocument > Make(SkWStream *dst, const SkSerialProcs *=nullptr, std::function< void(const SkPicture *)> onEndPage=nullptr)
sk_sp< const SkImage > image
bool IsCompileTimeConstant(const Expression &expr)
static SpvStorageClass_ get_storage_class(const Expression &expr)
static const int32_t SKSL_MAGIC
static bool types_match(const Type &a, const Type &b)
static SymbolTable * get_top_level_symbol_table(const FunctionDeclaration &anyFunc)
static bool is_out(ModifierFlags f)
bool ToSPIRV(Program &program, const ShaderCaps *caps, OutputStream &out)
static SpvStorageClass_ get_storage_class_for_global_variable(const Variable &var, SpvStorageClass_ fallbackStorageClass)
void write_stringstream(const StringStream &s, OutputStream &out)
static bool is_bool(const Type &type)
static bool is_float(const Type &type)
static bool is_unsigned(const Type &type)
skia_private::STArray< 2, std::unique_ptr< Statement > > StatementArray
static bool is_signed(const Type &type)
static SpvImageFormat layout_flags_to_image_format(LayoutFlags flags)
static bool is_vardecl_compile_time_constant(const VarDeclaration &varDecl)
static bool is_control_flow_op(SpvOp_ op)
static bool is_globally_reachable_op(SpvOp_ op)
static T pick_by_type(const Type &type, T ifFloat, T ifInt, T ifUInt, T ifBool)
static bool is_in(ModifierFlags f)
skia_private::FixedArray< 4, int8_t > ComponentArray
SkEnumBitMask< SkSL::LayoutFlag > LayoutFlags
void Log(const char *format,...) SK_PRINTF_LIKE(1
static void Normalize(char *s)
static uint32_t Hash(uint32_t key)
DEF_SWITCHES_START aot vmservice shared library name
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
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 running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
bool operator==(C p1, const scoped_nsprotocol< C > &p2)
static constexpr Color Min(Color c, float threshold)
skgpu::ganesh::TextureOp::Saturate Saturate
std::enable_if_t< sknonstd::is_bitmask_enum< E >::value, bool > constexpr Any(E e)
SI Vec< sizeof...(Ix), T > shuffle(const Vec< N, T > &)
static SkString to_string(int n)
int compare(const void *untyped_lhs, const void *untyped_rhs)
static const char header[]
@ SpvStorageClassUniformConstant
@ SpvStorageClassPushConstant
@ SpvStorageClassFunction
@ SpvStorageClassWorkgroup
enum SpvImageFormat_ SpvImageFormat
@ SpvSelectionControlMaskNone
@ SpvDecorationMatrixStride
@ SpvDecorationInputAttachmentIndex
@ SpvDecorationArrayStride
@ SpvDecorationBufferBlock
@ SpvDecorationNonWritable
@ SpvDecorationRelaxedPrecision
@ SpvDecorationNonReadable
@ SpvDecorationNoPerspective
@ SpvDecorationDescriptorSet
static const unsigned int SpvMagicNumber
@ SpvExecutionModeLocalSize
@ SpvExecutionModeOriginUpperLeft
@ SpvImageOperandsBiasMask
@ SpvImageOperandsSampleMask
@ SpvImageOperandsLodMask
@ SpvImageOperandsGradMask
@ SpvCapabilitySampledBuffer
@ SpvCapabilityInputAttachment
@ SpvCapabilityImageQuery
@ SpvFunctionControlMaskNone
@ SpvAddressingModelLogical
enum SpvStorageClass_ SpvStorageClass
@ SpvExecutionModelGLCompute
@ SpvExecutionModelFragment
@ SpvExecutionModelVertex
@ SpvMemorySemanticsWorkgroupMemoryMask
@ SpvMemorySemanticsUniformMemoryMask
@ SpvMemorySemanticsMaskNone
@ SpvMemorySemanticsAcquireReleaseMask
@ SpvOpFOrdGreaterThanEqual
@ SpvOpImageSampleExplicitLod
@ SpvOpImageSampleProjExplicitLod
@ SpvOpCompositeConstruct
@ SpvOpImageSampleProjImplicitLod
@ SpvOpShiftRightArithmetic
@ SpvOpVectorExtractDynamic
@ SpvOpImageSampleImplicitLod
static const unsigned int SpvVersion
static std::unique_ptr< Expression > LoadFloatBuffer(const Context &context, const SkSL::ShaderCaps &shaderCaps, Position position, std::unique_ptr< Expression > idx)
static bool IsVertex(ProgramKind kind)
static bool IsFragment(ProgramKind kind)
static bool IsCompute(ProgramKind kind)
std::shared_ptr< Context > fContext
std::unique_ptr< Pool > fPool
ProgramInterface fInterface
std::unique_ptr< SymbolTable > fSymbols
std::unique_ptr< std::string > fSource
std::unique_ptr< ProgramConfig > fConfig
uint32_t operator()(const SPIRVCodeGenerator::Instruction &key) const
static Word UniqueResult()
static Word RelaxedResult()
static Word Number(int32_t val)
Word(int32_t val, Kind kind)
static Word KeyedResult(int32_t key)
@ kDefaultPrecisionResult
@ kRelaxedPrecisionResult
static Word Result(const Type &type)
bool fMustDeclareFragmentFrontFacing
bool fRewriteMatrixVectorMultiply
std::shared_ptr< const fml::Mapping > data
#define TRACE_EVENT0(category_group, name)