96#ifdef SK_ENABLE_SPIRV_VALIDATION
97#include "spirv-tools/libspirv.hpp"
102#define kLast_Capability SpvCapabilityMultiViewport
148 :
INHERITED(context, caps, program, out) {}
153 enum IntrinsicOpcodeKind {
154 kGLSL_STD_450_IntrinsicOpcodeKind,
155 kSPIRV_IntrinsicOpcodeKind,
156 kSpecial_IntrinsicOpcodeKind,
157 kInvalid_IntrinsicOpcodeKind,
160 enum SpecialIntrinsic {
161 kAtan_SpecialIntrinsic,
162 kClamp_SpecialIntrinsic,
163 kMatrixCompMult_SpecialIntrinsic,
164 kMax_SpecialIntrinsic,
165 kMin_SpecialIntrinsic,
166 kMix_SpecialIntrinsic,
167 kMod_SpecialIntrinsic,
168 kDFdy_SpecialIntrinsic,
169 kSaturate_SpecialIntrinsic,
170 kSampledImage_SpecialIntrinsic,
171 kSmoothStep_SpecialIntrinsic,
172 kStep_SpecialIntrinsic,
173 kSubpassLoad_SpecialIntrinsic,
174 kTexture_SpecialIntrinsic,
175 kTextureGrad_SpecialIntrinsic,
176 kTextureLod_SpecialIntrinsic,
177 kTextureRead_SpecialIntrinsic,
178 kTextureWrite_SpecialIntrinsic,
179 kTextureWidth_SpecialIntrinsic,
180 kTextureHeight_SpecialIntrinsic,
181 kAtomicAdd_SpecialIntrinsic,
182 kAtomicLoad_SpecialIntrinsic,
183 kAtomicStore_SpecialIntrinsic,
184 kStorageBarrier_SpecialIntrinsic,
185 kWorkgroupBarrier_SpecialIntrinsic,
188 enum class Precision {
196 std::unique_ptr<SPIRVCodeGenerator::LValue> lvalue;
205 SpvId nextId(Precision precision);
209 SpvId getType(
const Type&
type,
const Layout& typeLayout,
const MemoryLayout& memoryLayout);
213 SpvId getFunctionParameterType(
const Type& parameterType,
const Layout& parameterLayout);
218 const Layout& typeLayout,
219 const MemoryLayout& memoryLayout,
224 void writeLayout(
const Layout& layout,
SpvId target, Position
pos);
226 void writeFieldLayout(
const Layout& layout,
SpvId target,
int member);
228 SpvId writeStruct(
const Type&
type,
const MemoryLayout& memoryLayout);
230 void writeProgramElement(
const ProgramElement& pe, OutputStream& out);
232 SpvId writeInterfaceBlock(
const InterfaceBlock& intf,
bool appendRTFlip =
true);
234 SpvId writeFunctionStart(
const FunctionDeclaration& f, OutputStream& out);
236 SpvId writeFunctionDeclaration(
const FunctionDeclaration& f, OutputStream& out);
238 SpvId writeFunction(
const FunctionDefinition& f, OutputStream& out);
240 bool writeGlobalVarDeclaration(
ProgramKind kind,
const VarDeclaration& v);
244 void writeVarDeclaration(
const VarDeclaration& var, OutputStream& out);
246 SpvId writeVariableReference(
const VariableReference& ref, OutputStream& out);
248 int findUniformFieldIndex(
const Variable& var)
const;
250 std::unique_ptr<LValue> getLValue(
const Expression& value, OutputStream& out);
252 SpvId writeExpression(
const Expression& expr, OutputStream& out);
254 SpvId writeIntrinsicCall(
const FunctionCall& c, OutputStream& out);
256 SpvId writeFunctionCallArgument(
const FunctionCall& call,
258 std::vector<TempVar>* tempVars,
260 SpvId* outSynthesizedSamplerId =
nullptr);
262 void copyBackTempVars(
const std::vector<TempVar>& tempVars, OutputStream& out);
264 SpvId writeFunctionCall(
const FunctionCall& c, OutputStream& out);
277 SpvId vectorize(
const Expression& expr,
int vectorSize, OutputStream& out);
287 SpvId writeSpecialIntrinsic(
const FunctionCall& c, SpecialIntrinsic kind, OutputStream& out);
288 SpvId writeAtomicIntrinsic(
const FunctionCall& c,
289 SpecialIntrinsic kind,
293 SpvId writeScalarToMatrixSplat(
const Type& matrixType,
SpvId scalarId, OutputStream& out);
298 SpvId castScalarToSignedInt(
SpvId inputId,
const Type& inputType,
const Type& outputType,
301 SpvId castScalarToUnsignedInt(
SpvId inputId,
const Type& inputType,
const Type& outputType,
304 SpvId castScalarToBoolean(
SpvId inputId,
const Type& inputType,
const Type& outputType,
307 SpvId castScalarToType(
SpvId inputExprId,
const Type& inputType,
const Type& outputType,
315 SpvId writeMatrixCopy(
SpvId src,
const Type& srcType,
const Type& dstType, OutputStream& out);
317 void addColumnEntry(
const Type& columnType,
320 int rows,
SpvId entry, OutputStream& out);
322 SpvId writeConstructorCompound(
const ConstructorCompound& c, OutputStream& out);
324 SpvId writeMatrixConstructor(
const ConstructorCompound& c, OutputStream& out);
326 SpvId writeVectorConstructor(
const ConstructorCompound& c, OutputStream& out);
328 SpvId writeCompositeConstructor(
const AnyConstructor& c, OutputStream& out);
330 SpvId writeConstructorDiagonalMatrix(
const ConstructorDiagonalMatrix& c, OutputStream& out);
332 SpvId writeConstructorMatrixResize(
const ConstructorMatrixResize& c, OutputStream& out);
334 SpvId writeConstructorScalarCast(
const ConstructorScalarCast& c, OutputStream& out);
336 SpvId writeConstructorSplat(
const ConstructorSplat& c, OutputStream& out);
338 SpvId writeConstructorCompoundCast(
const ConstructorCompoundCast& c, OutputStream& out);
340 SpvId writeFieldAccess(
const FieldAccess& f, OutputStream& out);
342 SpvId writeSwizzle(
const Expression& baseExpr,
346 SpvId writeSwizzle(
const Swizzle& swizzle, OutputStream& out);
358 SpvOp_ mergeOperator, OutputStream& out);
370 SpvId mergeComparisons(
SpvId comparison,
SpvId allComparisons, Operator op, OutputStream& out);
374 SpvId writeDecomposedMatrixVectorMultiply(
const Type& leftType,
376 const Type& rightType,
378 const Type& resultType,
381 SpvId writeComponentwiseMatrixUnary(
const Type& operandType,
387 SpvOp_ op, OutputStream& out);
389 SpvId writeBinaryOperation(
const Type& resultType,
const Type& operandType,
SpvId lhs,
391 SpvOp_ ifBool, OutputStream& out);
395 SpvId writeBinaryExpression(
const Type& leftType,
SpvId lhs, Operator op,
399 SpvId writeBinaryExpression(
const BinaryExpression&
b, OutputStream& out);
401 SpvId writeTernaryExpression(
const TernaryExpression& t, OutputStream& out);
403 SpvId writeIndexExpression(
const IndexExpression& expr, OutputStream& out);
405 SpvId writeLogicalAnd(
const Expression&
left,
const Expression&
right, OutputStream& out);
407 SpvId writeLogicalOr(
const Expression&
left,
const Expression&
right, OutputStream& out);
409 SpvId writePrefixExpression(
const PrefixExpression& p, OutputStream& out);
411 SpvId writePostfixExpression(
const PostfixExpression& p, OutputStream& out);
413 SpvId writeLiteral(
const Literal& f);
417 void writeStatement(
const Statement&
s, OutputStream& out);
419 void writeBlock(
const Block&
b, OutputStream& out);
421 void writeIfStatement(
const IfStatement& stmt, OutputStream& out);
423 void writeForStatement(
const ForStatement& f, OutputStream& out);
425 void writeDoStatement(
const DoStatement&
d, OutputStream& out);
427 void writeSwitchStatement(
const SwitchStatement&
s, OutputStream& out);
429 void writeReturnStatement(
const ReturnStatement& r, OutputStream& out);
431 void writeCapabilities(OutputStream& out);
433 void writeInstructions(
const Program& program, OutputStream& out);
435 void writeOpCode(
SpvOp_ opCode,
int length, OutputStream& out);
437 void writeWord(int32_t word, OutputStream& out);
439 void writeString(std::string_view
s, OutputStream& out);
441 void writeInstruction(
SpvOp_ opCode, OutputStream& out);
443 void writeInstruction(
SpvOp_ opCode, std::string_view
string, OutputStream& out);
445 void writeInstruction(
SpvOp_ opCode, int32_t word1, OutputStream& out);
447 void writeInstruction(
SpvOp_ opCode, int32_t word1, std::string_view
string,
450 void writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2, std::string_view
string,
453 void writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2, OutputStream& out);
455 void writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3,
458 void writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
461 void writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
462 int32_t word5, OutputStream& out);
464 void writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
465 int32_t word5, int32_t word6, OutputStream& out);
467 void writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
468 int32_t word5, int32_t word6, int32_t word7, OutputStream& out);
470 void writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2, int32_t word3, int32_t word4,
471 int32_t word5, int32_t word6, int32_t word7, int32_t word8,
479 SpvId writeInstruction(
487 bool operator==(
const Instruction& that)
const;
491 static Instruction BuildInstructionKey(
SpvOp_ opCode,
512 Instruction* resultTypeForInstruction(
const Instruction& instr);
513 int numComponentsForVecInstruction(
const Instruction& instr);
516 struct ConditionalOpCounts {
520 ConditionalOpCounts getConditionalOpCounts();
521 void pruneConditionalOps(ConditionalOpCounts
ops);
523 enum StraightLineLabelType {
534 kBranchIsOnPreviousLine,
537 enum BranchingLabelType {
547 kBranchesOnBothSides,
549 void writeLabel(
SpvId label, StraightLineLabelType
type, OutputStream& out);
550 void writeLabel(
SpvId label, BranchingLabelType
type, ConditionalOpCounts
ops,
554 MemoryLayout memoryLayoutForVariable(
const Variable&)
const;
556 struct EntrypointAdapter {
557 std::unique_ptr<FunctionDefinition> entrypointDef;
558 std::unique_ptr<FunctionDeclaration> entrypointDecl;
561 EntrypointAdapter writeEntrypointAdapter(
const FunctionDeclaration&
main);
563 struct UniformBuffer {
564 std::unique_ptr<InterfaceBlock> fInterfaceBlock;
565 std::unique_ptr<Variable> fInnerVariable;
566 std::unique_ptr<Type> fStruct;
569 void writeUniformBuffer(SymbolTable* topLevelSymbolTable);
571 void addRTFlipUniform(Position
pos);
573 std::unique_ptr<Expression> identifier(std::string_view
name);
575 std::tuple<const Variable*, const Variable*> synthesizeTextureAndSampler(
576 const Variable& combinedSampler);
580 uint64_t fCapabilities = 0;
582 SpvId fGLSLExtendedInstructions;
584 IntrinsicOpcodeKind opKind;
594 StringStream fGlobalInitializersBuffer;
595 StringStream fConstantBuffer;
596 StringStream fVariableBuffer;
597 StringStream fNameBuffer;
598 StringStream fDecorationBuffer;
602 bool fUseTextureSamplerPairs =
false;
603 struct SynthesizedTextureSamplerPair {
608 std::string fTextureName;
609 std::string fSamplerName;
610 std::unique_ptr<Variable> fTexture;
611 std::unique_ptr<Variable> fSampler;
614 fSynthesizedSamplerMap;
644 SpvId fCurrentBlock = 0;
647 bool fWroteRTFlip =
false;
649 SymbolTable fSynthetics{
true};
652 UniformBuffer fUniformBuffer;
653 std::vector<const VarDeclaration*> fTopLevelUniforms;
665bool SPIRVCodeGenerator::Instruction::operator==(
const SPIRVCodeGenerator::Instruction& that)
const {
666 return fOp == that.fOp &&
667 fResultKind == that.fResultKind &&
668 fWords == that.fWords;
673 uint32_t
hash =
key.fResultKind;
731SPIRVCodeGenerator::Intrinsic SPIRVCodeGenerator::getIntrinsic(
IntrinsicKind ik)
const {
733#define ALL_GLSL(x) Intrinsic{kGLSL_STD_450_IntrinsicOpcodeKind, GLSLstd450 ## x, \
734 GLSLstd450 ## x, GLSLstd450 ## x, GLSLstd450 ## x}
735#define BY_TYPE_GLSL(ifFloat, ifInt, ifUInt) Intrinsic{kGLSL_STD_450_IntrinsicOpcodeKind, \
736 GLSLstd450 ## ifFloat, \
737 GLSLstd450 ## ifInt, \
738 GLSLstd450 ## ifUInt, \
740#define ALL_SPIRV(x) Intrinsic{kSPIRV_IntrinsicOpcodeKind, \
741 SpvOp ## x, SpvOp ## x, SpvOp ## x, SpvOp ## x}
742#define BOOL_SPIRV(x) Intrinsic{kSPIRV_IntrinsicOpcodeKind, \
743 SpvOpUndef, SpvOpUndef, SpvOpUndef, SpvOp ## x}
744#define FLOAT_SPIRV(x) Intrinsic{kSPIRV_IntrinsicOpcodeKind, \
745 SpvOp ## x, SpvOpUndef, SpvOpUndef, SpvOpUndef}
746#define SPECIAL(x) Intrinsic{kSpecial_IntrinsicOpcodeKind, k ## x ## _SpecialIntrinsic, \
747 k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
748 k ## x ## _SpecialIntrinsic}
751 case k_round_IntrinsicKind:
return ALL_GLSL(Round);
752 case k_roundEven_IntrinsicKind:
return ALL_GLSL(RoundEven);
753 case k_trunc_IntrinsicKind:
return ALL_GLSL(Trunc);
754 case k_abs_IntrinsicKind:
return BY_TYPE_GLSL(FAbs, SAbs, SAbs);
755 case k_sign_IntrinsicKind:
return BY_TYPE_GLSL(FSign, SSign, SSign);
756 case k_floor_IntrinsicKind:
return ALL_GLSL(Floor);
757 case k_ceil_IntrinsicKind:
return ALL_GLSL(Ceil);
758 case k_fract_IntrinsicKind:
return ALL_GLSL(Fract);
759 case k_radians_IntrinsicKind:
return ALL_GLSL(Radians);
760 case k_degrees_IntrinsicKind:
return ALL_GLSL(Degrees);
761 case k_sin_IntrinsicKind:
return ALL_GLSL(Sin);
762 case k_cos_IntrinsicKind:
return ALL_GLSL(Cos);
763 case k_tan_IntrinsicKind:
return ALL_GLSL(Tan);
764 case k_asin_IntrinsicKind:
return ALL_GLSL(Asin);
765 case k_acos_IntrinsicKind:
return ALL_GLSL(Acos);
766 case k_atan_IntrinsicKind:
return SPECIAL(Atan);
767 case k_sinh_IntrinsicKind:
return ALL_GLSL(Sinh);
768 case k_cosh_IntrinsicKind:
return ALL_GLSL(Cosh);
769 case k_tanh_IntrinsicKind:
return ALL_GLSL(Tanh);
770 case k_asinh_IntrinsicKind:
return ALL_GLSL(Asinh);
771 case k_acosh_IntrinsicKind:
return ALL_GLSL(Acosh);
772 case k_atanh_IntrinsicKind:
return ALL_GLSL(Atanh);
773 case k_pow_IntrinsicKind:
return ALL_GLSL(Pow);
774 case k_exp_IntrinsicKind:
return ALL_GLSL(Exp);
775 case k_log_IntrinsicKind:
return ALL_GLSL(Log);
776 case k_exp2_IntrinsicKind:
return ALL_GLSL(Exp2);
777 case k_log2_IntrinsicKind:
return ALL_GLSL(Log2);
778 case k_sqrt_IntrinsicKind:
return ALL_GLSL(Sqrt);
779 case k_inverse_IntrinsicKind:
return ALL_GLSL(MatrixInverse);
780 case k_outerProduct_IntrinsicKind:
return ALL_SPIRV(OuterProduct);
781 case k_transpose_IntrinsicKind:
return ALL_SPIRV(Transpose);
782 case k_isinf_IntrinsicKind:
return ALL_SPIRV(IsInf);
783 case k_isnan_IntrinsicKind:
return ALL_SPIRV(IsNan);
784 case k_inversesqrt_IntrinsicKind:
return ALL_GLSL(InverseSqrt);
785 case k_determinant_IntrinsicKind:
return ALL_GLSL(Determinant);
786 case k_matrixCompMult_IntrinsicKind:
return SPECIAL(MatrixCompMult);
787 case k_matrixInverse_IntrinsicKind:
return ALL_GLSL(MatrixInverse);
788 case k_mod_IntrinsicKind:
return SPECIAL(Mod);
789 case k_modf_IntrinsicKind:
return ALL_GLSL(Modf);
790 case k_min_IntrinsicKind:
return SPECIAL(Min);
791 case k_max_IntrinsicKind:
return SPECIAL(Max);
792 case k_clamp_IntrinsicKind:
return SPECIAL(Clamp);
793 case k_saturate_IntrinsicKind:
return SPECIAL(Saturate);
795 case k_mix_IntrinsicKind:
return SPECIAL(Mix);
796 case k_step_IntrinsicKind:
return SPECIAL(Step);
797 case k_smoothstep_IntrinsicKind:
return SPECIAL(SmoothStep);
798 case k_fma_IntrinsicKind:
return ALL_GLSL(Fma);
799 case k_frexp_IntrinsicKind:
return ALL_GLSL(Frexp);
800 case k_ldexp_IntrinsicKind:
return ALL_GLSL(Ldexp);
802#define PACK(type) case k_pack##type##_IntrinsicKind: return ALL_GLSL(Pack##type); \
803 case k_unpack##type##_IntrinsicKind: return ALL_GLSL(Unpack##type)
811 case k_length_IntrinsicKind:
return ALL_GLSL(Length);
812 case k_distance_IntrinsicKind:
return ALL_GLSL(Distance);
813 case k_cross_IntrinsicKind:
return ALL_GLSL(Cross);
814 case k_normalize_IntrinsicKind:
return ALL_GLSL(Normalize);
815 case k_faceforward_IntrinsicKind:
return ALL_GLSL(FaceForward);
816 case k_reflect_IntrinsicKind:
return ALL_GLSL(Reflect);
817 case k_refract_IntrinsicKind:
return ALL_GLSL(Refract);
818 case k_bitCount_IntrinsicKind:
return ALL_SPIRV(BitCount);
819 case k_findLSB_IntrinsicKind:
return ALL_GLSL(FindILsb);
820 case k_findMSB_IntrinsicKind:
return BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
821 case k_dFdx_IntrinsicKind:
return FLOAT_SPIRV(DPdx);
822 case k_dFdy_IntrinsicKind:
return SPECIAL(DFdy);
823 case k_fwidth_IntrinsicKind:
return FLOAT_SPIRV(Fwidth);
825 case k_sample_IntrinsicKind:
return SPECIAL(Texture);
826 case k_sampleGrad_IntrinsicKind:
return SPECIAL(TextureGrad);
827 case k_sampleLod_IntrinsicKind:
return SPECIAL(TextureLod);
828 case k_subpassLoad_IntrinsicKind:
return SPECIAL(SubpassLoad);
830 case k_textureRead_IntrinsicKind:
return SPECIAL(TextureRead);
831 case k_textureWrite_IntrinsicKind:
return SPECIAL(TextureWrite);
832 case k_textureWidth_IntrinsicKind:
return SPECIAL(TextureWidth);
833 case k_textureHeight_IntrinsicKind:
return SPECIAL(TextureHeight);
835 case k_floatBitsToInt_IntrinsicKind:
return ALL_SPIRV(Bitcast);
836 case k_floatBitsToUint_IntrinsicKind:
return ALL_SPIRV(Bitcast);
837 case k_intBitsToFloat_IntrinsicKind:
return ALL_SPIRV(Bitcast);
838 case k_uintBitsToFloat_IntrinsicKind:
return ALL_SPIRV(Bitcast);
840 case k_any_IntrinsicKind:
return BOOL_SPIRV(Any);
841 case k_all_IntrinsicKind:
return BOOL_SPIRV(All);
842 case k_not_IntrinsicKind:
return BOOL_SPIRV(LogicalNot);
844 case k_equal_IntrinsicKind:
845 return Intrinsic{kSPIRV_IntrinsicOpcodeKind,
850 case k_notEqual_IntrinsicKind:
851 return Intrinsic{kSPIRV_IntrinsicOpcodeKind,
856 case k_lessThan_IntrinsicKind:
857 return Intrinsic{kSPIRV_IntrinsicOpcodeKind,
862 case k_lessThanEqual_IntrinsicKind:
863 return Intrinsic{kSPIRV_IntrinsicOpcodeKind,
868 case k_greaterThan_IntrinsicKind:
869 return Intrinsic{kSPIRV_IntrinsicOpcodeKind,
874 case k_greaterThanEqual_IntrinsicKind:
875 return Intrinsic{kSPIRV_IntrinsicOpcodeKind,
881 case k_atomicAdd_IntrinsicKind:
return SPECIAL(AtomicAdd);
882 case k_atomicLoad_IntrinsicKind:
return SPECIAL(AtomicLoad);
883 case k_atomicStore_IntrinsicKind:
return SPECIAL(AtomicStore);
885 case k_storageBarrier_IntrinsicKind:
return SPECIAL(StorageBarrier);
886 case k_workgroupBarrier_IntrinsicKind:
return SPECIAL(WorkgroupBarrier);
888 return Intrinsic{kInvalid_IntrinsicOpcodeKind, 0, 0, 0, 0};
892void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
893 out.write((
const char*) &word,
sizeof(word));
897 return (
type.isScalar() ||
type.isVector() ||
type.isMatrix()) &&
898 type.componentType().isFloat();
902 return (
type.isScalar() ||
type.isVector()) &&
type.componentType().isSigned();
906 return (
type.isScalar() ||
type.isVector()) &&
type.componentType().isUnsigned();
910 return (
type.isScalar() ||
type.isVector()) &&
type.componentType().isBoolean();
998void SPIRVCodeGenerator::writeOpCode(
SpvOp_ opCode,
int length, OutputStream& out) {
1001 bool foundDeadCode =
false;
1004 foundDeadCode = (fCurrentBlock == 0);
1007 foundDeadCode = (fCurrentBlock == 0);
1010 if (foundDeadCode) {
1013 this->writeLabel(this->nextId(
nullptr), kBranchlessBlock, out);
1016 this->writeWord((
length << 16) | opCode, out);
1019void SPIRVCodeGenerator::writeLabel(
SpvId label, StraightLineLabelType, OutputStream& out) {
1022 fCurrentBlock = label;
1023 this->writeInstruction(
SpvOpLabel, label, out);
1026void SPIRVCodeGenerator::writeLabel(
SpvId label, BranchingLabelType
type,
1027 ConditionalOpCounts
ops, OutputStream& out) {
1029 case kBranchIsBelow:
1030 case kBranchesOnBothSides:
1034 fStoreCache.
reset();
1037 case kBranchIsAbove:
1041 this->pruneConditionalOps(
ops);
1046 this->writeLabel(label, kBranchlessBlock, out);
1049void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, OutputStream& out) {
1050 this->writeOpCode(opCode, 1, out);
1053void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, OutputStream& out) {
1054 this->writeOpCode(opCode, 2, out);
1055 this->writeWord(word1, out);
1058void SPIRVCodeGenerator::writeString(std::string_view
s, OutputStream& out) {
1059 out.write(
s.data(),
s.length());
1060 switch (
s.length() % 4) {
1071 this->writeWord(0, out);
1076void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, std::string_view
string,
1077 OutputStream& out) {
1078 this->writeOpCode(opCode, 1 + (
string.
length() + 4) / 4, out);
1079 this->writeString(
string, out);
1082void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, std::string_view
string,
1083 OutputStream& out) {
1084 this->writeOpCode(opCode, 2 + (
string.
length() + 4) / 4, out);
1085 this->writeWord(word1, out);
1086 this->writeString(
string, out);
1089void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2,
1090 std::string_view
string, OutputStream& out) {
1091 this->writeOpCode(opCode, 3 + (
string.
length() + 4) / 4, out);
1092 this->writeWord(word1, out);
1093 this->writeWord(word2, out);
1094 this->writeString(
string, out);
1097void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2,
1098 OutputStream& out) {
1099 this->writeOpCode(opCode, 3, out);
1100 this->writeWord(word1, out);
1101 this->writeWord(word2, out);
1104void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2,
1105 int32_t word3, OutputStream& out) {
1106 this->writeOpCode(opCode, 4, out);
1107 this->writeWord(word1, out);
1108 this->writeWord(word2, out);
1109 this->writeWord(word3, out);
1112void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2,
1113 int32_t word3, int32_t word4, OutputStream& out) {
1114 this->writeOpCode(opCode, 5, out);
1115 this->writeWord(word1, out);
1116 this->writeWord(word2, out);
1117 this->writeWord(word3, out);
1118 this->writeWord(word4, out);
1121void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2,
1122 int32_t word3, int32_t word4, int32_t word5,
1123 OutputStream& out) {
1124 this->writeOpCode(opCode, 6, out);
1125 this->writeWord(word1, out);
1126 this->writeWord(word2, out);
1127 this->writeWord(word3, out);
1128 this->writeWord(word4, out);
1129 this->writeWord(word5, out);
1132void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2,
1133 int32_t word3, int32_t word4, int32_t word5,
1134 int32_t word6, OutputStream& out) {
1135 this->writeOpCode(opCode, 7, out);
1136 this->writeWord(word1, out);
1137 this->writeWord(word2, out);
1138 this->writeWord(word3, out);
1139 this->writeWord(word4, out);
1140 this->writeWord(word5, out);
1141 this->writeWord(word6, out);
1144void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2,
1145 int32_t word3, int32_t word4, int32_t word5,
1146 int32_t word6, int32_t word7, OutputStream& out) {
1147 this->writeOpCode(opCode, 8, out);
1148 this->writeWord(word1, out);
1149 this->writeWord(word2, out);
1150 this->writeWord(word3, out);
1151 this->writeWord(word4, out);
1152 this->writeWord(word5, out);
1153 this->writeWord(word6, out);
1154 this->writeWord(word7, out);
1157void SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode, int32_t word1, int32_t word2,
1158 int32_t word3, int32_t word4, int32_t word5,
1159 int32_t word6, int32_t word7, int32_t word8,
1160 OutputStream& out) {
1161 this->writeOpCode(opCode, 9, out);
1162 this->writeWord(word1, out);
1163 this->writeWord(word2, out);
1164 this->writeWord(word3, out);
1165 this->writeWord(word4, out);
1166 this->writeWord(word5, out);
1167 this->writeWord(word6, out);
1168 this->writeWord(word7, out);
1169 this->writeWord(word8, out);
1172SPIRVCodeGenerator::Instruction SPIRVCodeGenerator::BuildInstructionKey(
SpvOp_ opCode,
1177 key.fWords.resize(words.
size());
1180 for (
int index = 0; index < words.
size(); ++index) {
1181 const Word&
word = words[index];
1182 key.fWords[index] =
word.fValue;
1183 if (
word.isResult()) {
1192SpvId SPIRVCodeGenerator::writeInstruction(
SpvOp_ opCode,
1194 OutputStream& out) {
1200 Instruction
key = BuildInstructionKey(opCode, words);
1201 if (
SpvId* cachedOp = fOpCache.find(
key)) {
1206 Precision precision = Precision::kDefault;
1208 switch (
key.fResultKind) {
1211 result = this->nextId(Precision::kDefault);
1221 precision = Precision::kRelaxed;
1229 result = this->nextId(precision);
1245 this->writeOpCode(opCode, words.
size() + 1, out);
1246 for (
const Word& word : words) {
1247 if (
word.isResult()) {
1249 this->writeWord(
result, out);
1251 this->writeWord(
word.fValue, out);
1260 Precision precision,
1262 OutputStream& out) {
1264 if (
SpvId* cachedOp = fStoreCache.
find(pointer)) {
1277 OutputStream& out) {
1279 this->writeInstruction(
SpvOpStore, pointer, value, out);
1284 fStoreCache.
set(pointer, value);
1289SpvId SPIRVCodeGenerator::writeOpConstantTrue(
const Type&
type) {
1295SpvId SPIRVCodeGenerator::writeOpConstantFalse(
const Type&
type) {
1301SpvId SPIRVCodeGenerator::writeOpConstant(
const Type&
type, int32_t valueBits) {
1302 return this->writeInstruction(
1308SpvId SPIRVCodeGenerator::writeOpConstantComposite(
const Type&
type,
1316 words.push_back(value);
1322 Instruction* instr = fSpvIdCache.
find(value);
1326 switch (instr->fOp) {
1335 for (
int i = 2; i < instr->fWords.size(); ++i) {
1336 if (!this->toConstants(instr->fWords[i], constants)) {
1349 if (!this->toConstants(value, constants)) {
1356SpvId SPIRVCodeGenerator::writeOpCompositeConstruct(
const Type&
type,
1358 OutputStream& out) {
1360 if (
type.isVector()) {
1362 if (this->toConstants(
SkSpan(values), &constants)) {
1364 return this->writeOpConstantComposite(
type, constants);
1369 if (
type.isMatrix()) {
1371 if (this->toConstants(
SkSpan(values), &constants)) {
1376 for (
int index=0; index <
type.columns(); ++index) {
1379 columnIDs.
push_back(this->writeOpConstantComposite(vecType, columnConstants));
1382 return this->writeOpConstantComposite(
type, columnIDs);
1387 words.push_back(this->getType(
type));
1390 words.push_back(value);
1396SPIRVCodeGenerator::Instruction* SPIRVCodeGenerator::resultTypeForInstruction(
1397 const Instruction& instr) {
1403 switch (instr.fOp) {
1418 Instruction* typeInstr = fSpvIdCache.
find(instr.fWords[resultTypeWord]);
1423int SPIRVCodeGenerator::numComponentsForVecInstruction(
const Instruction& instr) {
1425 Instruction* typeInstr = this->resultTypeForInstruction(instr);
1436SpvId SPIRVCodeGenerator::toComponent(
SpvId id,
int component) {
1437 Instruction* instr = fSpvIdCache.
find(
id);
1444 return instr->fWords[2 + component];
1449 Instruction* composedType = fSpvIdCache.
find(instr->fWords[0]);
1455 return instr->fWords[2 + component];
1460 for (
int index = 2; index < instr->fWords.size(); ++index) {
1461 int32_t currentWord = instr->fWords[index];
1464 Instruction* subinstr = fSpvIdCache.
find(currentWord);
1469 int numComponents = this->numComponentsForVecInstruction(*subinstr);
1470 if (component < numComponents) {
1471 if (numComponents == 1) {
1477 return this->toComponent(currentWord, component);
1481 component -= numComponents;
1483 SkDEBUGFAIL(
"component index goes past the end of this composite value");
1489SpvId SPIRVCodeGenerator::writeOpCompositeExtract(
const Type&
type,
1492 OutputStream& out) {
1498 return this->writeInstruction(
1504SpvId SPIRVCodeGenerator::writeOpCompositeExtract(
const Type&
type,
1508 OutputStream& out) {
1512 return this->writeOpCompositeExtract(
type,
result, componentB, out);
1515 {this->getType(
type),
1523void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
1525 if (fCapabilities & bit) {
1533 return this->nextId(
type &&
type->hasPrecision() && !
type->highPrecision()
1534 ? Precision::kRelaxed
1538SpvId SPIRVCodeGenerator::nextId(Precision precision) {
1539 if (precision == Precision::kRelaxed && !
fProgram.
fConfig->fSettings.fForceHighPrecision) {
1546SpvId SPIRVCodeGenerator::writeStruct(
const Type&
type,
const MemoryLayout& memoryLayout) {
1548 if (
SpvId* cachedStructId = fStructMap.find(&
type)) {
1549 return *cachedStructId;
1556 for (
const auto& f :
type.fields()) {
1557 words.push_back(this->getType(*
f.fType,
f.fLayout, memoryLayout));
1560 this->writeInstruction(
SpvOpName, resultId,
type.name(), fNameBuffer);
1561 fStructMap.set(&
type, resultId);
1564 for (int32_t i = 0; i < (int32_t)
type.fields().size(); i++) {
1565 const Field& field =
type.fields()[i];
1566 if (!memoryLayout.isSupported(*field.fType)) {
1568 "' is not permitted here");
1571 size_t size = memoryLayout.size(*field.fType);
1572 size_t alignment = memoryLayout.alignment(*field.fType);
1573 const Layout& fieldLayout = field.fLayout;
1574 if (fieldLayout.fOffset >= 0) {
1575 if (fieldLayout.fOffset < (
int)
offset) {
1577 std::string(field.fName) +
"' must be at least " + std::to_string(
offset));
1579 if (fieldLayout.fOffset % alignment) {
1581 "offset of field '" + std::string(field.fName) +
1582 "' must be a multiple of " + std::to_string(alignment));
1584 offset = fieldLayout.fOffset;
1586 size_t mod =
offset % alignment;
1588 offset += alignment - mod;
1591 this->writeInstruction(
SpvOpMemberName, resultId, i, field.fName, fNameBuffer);
1592 this->writeFieldLayout(fieldLayout, resultId, i);
1593 if (field.fLayout.fBuiltin < 0) {
1597 if (field.fType->isMatrix()) {
1601 (
SpvId) memoryLayout.stride(*field.fType),
1604 if (!field.fType->highPrecision()) {
1609 if ((field.fType->isArray() || field.fType->isStruct()) &&
offset % alignment != 0) {
1623 switch (
flags.value()) {
1640SpvId SPIRVCodeGenerator::getType(
const Type& rawType,
1641 const Layout& typeLayout,
1642 const MemoryLayout& memoryLayout) {
1645 switch (
type->typeKind()) {
1651 if (
type->isBoolean()) {
1654 if (
type->isSigned()) {
1655 return this->writeInstruction(
1660 if (
type->isUnsigned()) {
1661 return this->writeInstruction(
1666 if (
type->isFloat()) {
1667 return this->writeInstruction(
1672 SkDEBUGFAILF(
"unrecognized scalar type '%s'",
type->description().c_str());
1676 SpvId scalarTypeId = this->getType(
type->componentType(), typeLayout, memoryLayout);
1677 return this->writeInstruction(
1686 return this->writeInstruction(
1692 if (!memoryLayout.isSupported(*
type)) {
1694 "' is not permitted here");
1697 size_t stride = memoryLayout.stride(*
type);
1698 SpvId typeId = this->getType(
type->componentType(), typeLayout, memoryLayout);
1700 if (
type->isUnsizedArray()) {
1716 return this->writeStruct(*
type, memoryLayout);
1725 SpvId imageTypeId = this->getType(
type->textureType(), typeLayout, memoryLayout);
1767SpvId SPIRVCodeGenerator::getFunctionType(
const FunctionDeclaration&
function) {
1770 words.push_back(this->getType(
function.returnType()));
1771 for (
const Variable* parameter :
function.parameters()) {
1772 if (fUseTextureSamplerPairs && parameter->type().isSampler()) {
1773 words.push_back(this->getFunctionParameterType(parameter->type().textureType(),
1774 parameter->layout()));
1778 words.push_back(this->getFunctionParameterType(parameter->type(), parameter->layout()));
1784SpvId SPIRVCodeGenerator::getFunctionParameterType(
const Type& parameterType,
1785 const Layout& parameterLayout) {
1825 return this->getPointerType(parameterType,
1827 this->memoryLayoutForStorageClass(storageClass),
1832 return this->getPointerType(
type,
1834 this->memoryLayoutForStorageClass(storageClass),
1839 const Layout& typeLayout,
1840 const MemoryLayout& memoryLayout,
1845 this->getType(
type, typeLayout, memoryLayout)},
1849SpvId SPIRVCodeGenerator::writeExpression(
const Expression& expr, OutputStream& out) {
1850 switch (expr.kind()) {
1851 case Expression::Kind::kBinary:
1852 return this->writeBinaryExpression(expr.as<BinaryExpression>(), out);
1853 case Expression::Kind::kConstructorArrayCast:
1854 return this->writeExpression(*expr.as<ConstructorArrayCast>().argument(), out);
1855 case Expression::Kind::kConstructorArray:
1856 case Expression::Kind::kConstructorStruct:
1857 return this->writeCompositeConstructor(expr.asAnyConstructor(), out);
1858 case Expression::Kind::kConstructorDiagonalMatrix:
1859 return this->writeConstructorDiagonalMatrix(expr.as<ConstructorDiagonalMatrix>(), out);
1860 case Expression::Kind::kConstructorMatrixResize:
1861 return this->writeConstructorMatrixResize(expr.as<ConstructorMatrixResize>(), out);
1862 case Expression::Kind::kConstructorScalarCast:
1863 return this->writeConstructorScalarCast(expr.as<ConstructorScalarCast>(), out);
1864 case Expression::Kind::kConstructorSplat:
1865 return this->writeConstructorSplat(expr.as<ConstructorSplat>(), out);
1866 case Expression::Kind::kConstructorCompound:
1867 return this->writeConstructorCompound(expr.as<ConstructorCompound>(), out);
1868 case Expression::Kind::kConstructorCompoundCast:
1869 return this->writeConstructorCompoundCast(expr.as<ConstructorCompoundCast>(), out);
1870 case Expression::Kind::kEmpty:
1872 case Expression::Kind::kFieldAccess:
1873 return this->writeFieldAccess(expr.as<FieldAccess>(), out);
1874 case Expression::Kind::kFunctionCall:
1875 return this->writeFunctionCall(expr.as<FunctionCall>(), out);
1876 case Expression::Kind::kLiteral:
1877 return this->writeLiteral(expr.as<Literal>());
1878 case Expression::Kind::kPrefix:
1879 return this->writePrefixExpression(expr.as<PrefixExpression>(), out);
1880 case Expression::Kind::kPostfix:
1881 return this->writePostfixExpression(expr.as<PostfixExpression>(), out);
1882 case Expression::Kind::kSwizzle:
1883 return this->writeSwizzle(expr.as<Swizzle>(), out);
1884 case Expression::Kind::kVariableReference:
1885 return this->writeVariableReference(expr.as<VariableReference>(), out);
1886 case Expression::Kind::kTernary:
1887 return this->writeTernaryExpression(expr.as<TernaryExpression>(), out);
1888 case Expression::Kind::kIndex:
1889 return this->writeIndexExpression(expr.as<IndexExpression>(), out);
1890 case Expression::Kind::kSetting:
1891 return this->writeExpression(*expr.as<Setting>().toLiteral(
fCaps), out);
1893 SkDEBUGFAILF(
"unsupported expression: %s", expr.description().c_str());
1899SpvId SPIRVCodeGenerator::writeIntrinsicCall(
const FunctionCall& c, OutputStream& out) {
1900 const FunctionDeclaration&
function = c.function();
1901 Intrinsic intrinsic = this->getIntrinsic(
function.intrinsicKind());
1902 if (intrinsic.opKind == kInvalid_IntrinsicOpcodeKind) {
1907 const ExpressionArray& arguments = c.arguments();
1908 int32_t intrinsicId = intrinsic.floatOp;
1909 if (!arguments.empty()) {
1910 const Type&
type = arguments[0]->type();
1911 if (intrinsic.opKind == kSpecial_IntrinsicOpcodeKind) {
1915 intrinsic.unsignedOp, intrinsic.boolOp);
1918 switch (intrinsic.opKind) {
1919 case kGLSL_STD_450_IntrinsicOpcodeKind: {
1923 std::vector<TempVar> tempVars;
1924 for (
int i = 0; i < arguments.size(); i++) {
1925 argumentIds.
push_back(this->writeFunctionCallArgument(c, i, &tempVars, out));
1928 this->writeWord(this->getType(c.type()), out);
1929 this->writeWord(
result, out);
1930 this->writeWord(fGLSLExtendedInstructions, out);
1931 this->writeWord(intrinsicId, out);
1932 for (
SpvId id : argumentIds) {
1933 this->writeWord(
id, out);
1935 this->copyBackTempVars(tempVars, out);
1938 case kSPIRV_IntrinsicOpcodeKind: {
1940 if (intrinsicId ==
SpvOpDot && arguments[0]->
type().isScalar()) {
1946 std::vector<TempVar> tempVars;
1947 for (
int i = 0; i < arguments.size(); i++) {
1948 argumentIds.
push_back(this->writeFunctionCallArgument(c, i, &tempVars, out));
1950 if (!c.type().isVoid()) {
1951 this->writeOpCode((
SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
1952 this->writeWord(this->getType(c.type()), out);
1953 this->writeWord(
result, out);
1955 this->writeOpCode((
SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
1957 for (
SpvId id : argumentIds) {
1958 this->writeWord(
id, out);
1960 this->copyBackTempVars(tempVars, out);
1963 case kSpecial_IntrinsicOpcodeKind:
1964 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
1972SpvId SPIRVCodeGenerator::vectorize(
const Expression& arg,
int vectorSize, OutputStream& out) {
1973 SkASSERT(vectorSize >= 1 && vectorSize <= 4);
1974 const Type& argType = arg.type();
1975 if (argType.isScalar() && vectorSize > 1) {
1976 ConstructorSplat splat{arg.fPosition,
1977 argType.toCompound(
fContext, vectorSize, 1),
1979 return this->writeConstructorSplat(splat, out);
1982 SkASSERT(vectorSize == argType.columns());
1983 return this->writeExpression(arg, out);
1986TArray<SpvId> SPIRVCodeGenerator::vectorize(
const ExpressionArray&
args, OutputStream& out) {
1988 for (
const auto&
a :
args) {
1989 if (
a->type().isVector()) {
1990 if (vectorSize > 1) {
1991 SkASSERT(
a->type().columns() == vectorSize);
1993 vectorSize =
a->type().columns();
1999 for (
const auto& arg :
args) {
2000 result.push_back(this->vectorize(*arg, vectorSize, out));
2005void SPIRVCodeGenerator::writeGLSLExtendedInstruction(
const Type&
type,
SpvId id,
SpvId floatInst,
2008 OutputStream& out) {
2010 this->writeWord(this->getType(
type), out);
2011 this->writeWord(
id, out);
2012 this->writeWord(fGLSLExtendedInstructions, out);
2015 this->writeWord(
a, out);
2019SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(
const FunctionCall& c, SpecialIntrinsic kind,
2020 OutputStream& out) {
2021 const ExpressionArray& arguments = c.arguments();
2022 const Type& callType = c.type();
2025 case kAtan_SpecialIntrinsic: {
2027 for (
const std::unique_ptr<Expression>& arg : arguments) {
2028 argumentIds.
push_back(this->writeExpression(*arg, out));
2031 this->writeWord(this->getType(callType), out);
2032 this->writeWord(
result, out);
2033 this->writeWord(fGLSLExtendedInstructions, out);
2035 for (
SpvId id : argumentIds) {
2036 this->writeWord(
id, out);
2040 case kSampledImage_SpecialIntrinsic: {
2042 SpvId img = this->writeExpression(*arguments[0], out);
2043 SpvId sampler = this->writeExpression(*arguments[1], out);
2045 this->getType(callType),
2052 case kSubpassLoad_SpecialIntrinsic: {
2053 SpvId img = this->writeExpression(*arguments[0], out);
2054 ExpressionArray
args;
2055 args.reserve_exact(2);
2059 SpvId coords = this->writeExpression(ctor, out);
2060 if (arguments.size() == 1) {
2062 this->getType(callType),
2069 SpvId sample = this->writeExpression(*arguments[1], out);
2071 this->getType(callType),
2081 case kTexture_SpecialIntrinsic: {
2083 const Type& arg1Type = arguments[1]->type();
2084 switch (arguments[0]->
type().dimensions()) {
2113 SpvId sampler = this->writeExpression(*arguments[0], out);
2114 SpvId uv = this->writeExpression(*arguments[1], out);
2115 if (arguments.size() == 3) {
2116 this->writeInstruction(op,
type,
result, sampler, uv,
2118 this->writeExpression(*arguments[2], out),
2125 this->writeInstruction(op,
type,
result, sampler, uv,
2128 this->writeInstruction(op,
type,
result, sampler, uv,
2134 case kTextureGrad_SpecialIntrinsic: {
2142 SpvId sampler = this->writeExpression(*arguments[0], out);
2143 SpvId uv = this->writeExpression(*arguments[1], out);
2144 SpvId dPdx = this->writeExpression(*arguments[2], out);
2145 SpvId dPdy = this->writeExpression(*arguments[3], out);
2150 case kTextureLod_SpecialIntrinsic: {
2155 const Type& arg1Type = arguments[1]->type();
2162 SpvId sampler = this->writeExpression(*arguments[0], out);
2163 SpvId uv = this->writeExpression(*arguments[1], out);
2164 this->writeInstruction(op,
type,
result, sampler, uv,
2166 this->writeExpression(*arguments[2], out),
2170 case kTextureRead_SpecialIntrinsic: {
2175 SpvId image = this->writeExpression(*arguments[0], out);
2176 SpvId coord = this->writeExpression(*arguments[1], out);
2178 const Type& arg0Type = arguments[0]->type();
2181 switch (arg0Type.textureAccess()) {
2194 SkDEBUGFAIL(
"'textureRead' called on writeonly texture type");
2200 case kTextureWrite_SpecialIntrinsic: {
2205 SpvId image = this->writeExpression(*arguments[0], out);
2206 SpvId coord = this->writeExpression(*arguments[1], out);
2207 SpvId texel = this->writeExpression(*arguments[2], out);
2212 case kTextureWidth_SpecialIntrinsic:
2213 case kTextureHeight_SpecialIntrinsic: {
2218 SpvId dims = this->nextId(
nullptr);
2219 SpvId image = this->writeExpression(*arguments[0], out);
2223 int32_t index = (kind == kTextureWidth_SpecialIntrinsic) ? 0 : 1;
2227 case kMod_SpecialIntrinsic: {
2230 const Type& operandType = arguments[0]->type();
2233 this->writeOpCode(op, 5, out);
2234 this->writeWord(this->getType(operandType), out);
2235 this->writeWord(
result, out);
2236 this->writeWord(
args[0], out);
2237 this->writeWord(
args[1], out);
2240 case kDFdy_SpecialIntrinsic: {
2241 SpvId fn = this->writeExpression(*arguments[0], out);
2243 this->writeWord(this->getType(callType), out);
2244 this->writeWord(
result, out);
2245 this->writeWord(fn, out);
2247 this->addRTFlipUniform(c.fPosition);
2249 for (
int index = 0; index < callType.columns(); ++index) {
2253 componentArray, out);
2254 SpvId flipped = this->nextId(&callType);
2255 this->writeInstruction(
SpvOpFMul, this->getType(callType), flipped,
result,
2261 case kClamp_SpecialIntrinsic: {
2268 case kMax_SpecialIntrinsic: {
2275 case kMin_SpecialIntrinsic: {
2282 case kMix_SpecialIntrinsic: {
2285 if (arguments[2]->
type().componentType().isBoolean()) {
2287 SpvId falseId = this->writeExpression(*arguments[0], out);
2288 SpvId trueId = this->writeExpression(*arguments[1], out);
2289 SpvId conditionId = this->writeExpression(*arguments[2], out);
2291 conditionId, trueId, falseId, out);
2298 case kSaturate_SpecialIntrinsic: {
2300 ExpressionArray finalArgs;
2301 finalArgs.reserve_exact(3);
2302 finalArgs.push_back(arguments[0]->clone());
2310 case kSmoothStep_SpecialIntrinsic: {
2317 case kStep_SpecialIntrinsic: {
2324 case kMatrixCompMult_SpecialIntrinsic: {
2326 SpvId lhs = this->writeExpression(*arguments[0], out);
2327 SpvId rhs = this->writeExpression(*arguments[1], out);
2328 result = this->writeComponentwiseMatrixBinary(callType, lhs, rhs,
SpvOpFMul, out);
2331 case kAtomicAdd_SpecialIntrinsic:
2332 case kAtomicLoad_SpecialIntrinsic:
2333 case kAtomicStore_SpecialIntrinsic:
2334 result = this->writeAtomicIntrinsic(c, kind,
result, out);
2336 case kStorageBarrier_SpecialIntrinsic:
2337 case kWorkgroupBarrier_SpecialIntrinsic: {
2342 int32_t memSemMask = (kind == kStorageBarrier_SpecialIntrinsic)
2359SpvId SPIRVCodeGenerator::writeAtomicIntrinsic(
const FunctionCall& c,
2360 SpecialIntrinsic kind,
2362 OutputStream& out) {
2363 const ExpressionArray& arguments = c.arguments();
2366 std::unique_ptr<LValue> atomicPtr = this->getLValue(*arguments[0], out);
2367 SpvId atomicPtrId = atomicPtr->getPointer();
2368 if (atomicPtrId ==
NA) {
2369 SkDEBUGFAILF(
"atomic intrinsic expected a pointer argument: %s",
2370 arguments[0]->description().c_str());
2380 switch (atomicPtr->storageClass()) {
2390 SkDEBUGFAILF(
"atomic argument has invalid storage class: %d",
2391 atomicPtr->storageClass());
2397 SpvId relaxedMemoryOrderId =
2401 case kAtomicAdd_SpecialIntrinsic:
2404 this->getType(c.type()),
2408 relaxedMemoryOrderId,
2409 this->writeExpression(*arguments[1], out),
2412 case kAtomicLoad_SpecialIntrinsic:
2415 this->getType(c.type()),
2419 relaxedMemoryOrderId,
2422 case kAtomicStore_SpecialIntrinsic:
2427 relaxedMemoryOrderId,
2428 this->writeExpression(*arguments[1], out),
2438SpvId SPIRVCodeGenerator::writeFunctionCallArgument(
const FunctionCall& call,
2440 std::vector<TempVar>* tempVars,
2442 SpvId* outSynthesizedSamplerId) {
2443 const FunctionDeclaration& funcDecl =
call.function();
2444 const Expression& arg = *
call.arguments()[argIndex];
2445 ModifierFlags paramFlags = funcDecl.parameters()[argIndex]->modifierFlags();
2453 if (
is_out(paramFlags)) {
2454 std::unique_ptr<LValue> lv = this->getLValue(arg, out);
2459 if (
is_in(paramFlags)) {
2460 tmpValueId = lv->load(out);
2462 tmpVar = this->nextId(&arg.type());
2463 tempVars->push_back(TempVar{tmpVar, &arg.type(), std::move(lv)});
2464 }
else if (funcDecl.isIntrinsic()) {
2466 return this->writeExpression(arg, out);
2467 }
else if (arg.is<VariableReference>() &&
2478 const Variable* var = arg.as<VariableReference>().variable();
2481 if (fUseTextureSamplerPairs && var->type().isSampler()) {
2482 if (
const auto* p = fSynthesizedSamplerMap.find(var)) {
2485 SpvId* img = fVariableMap.find((*p)->fTexture.get());
2486 SpvId* sampler = fVariableMap.find((*p)->fSampler.get());
2490 *outSynthesizedSamplerId = *sampler;
2493 SkDEBUGFAIL(
"sampler missing from fSynthesizedSamplerMap");
2496 SpvId* entry = fVariableMap.find(var);
2497 SkASSERTF(entry,
"%s", arg.description().c_str());
2502 tmpValueId = this->writeExpression(arg, out);
2503 tmpVar = this->nextId(
nullptr);
2510 if (tmpValueId !=
NA) {
2516void SPIRVCodeGenerator::copyBackTempVars(
const std::vector<TempVar>& tempVars, OutputStream& out) {
2517 for (
const TempVar& tempVar : tempVars) {
2518 SpvId load = this->nextId(tempVar.type);
2519 this->writeInstruction(
SpvOpLoad, this->getType(*tempVar.type),
load, tempVar.spvId, out);
2520 tempVar.lvalue->store(
load, out);
2524SpvId SPIRVCodeGenerator::writeFunctionCall(
const FunctionCall& c, OutputStream& out) {
2525 const FunctionDeclaration&
function = c.function();
2527 return this->writeIntrinsicCall(c, out);
2529 const ExpressionArray& arguments = c.arguments();
2533 "' is not defined");
2537 std::vector<TempVar> tempVars;
2540 for (
int i = 0; i < arguments.size(); i++) {
2542 argumentIds.
push_back(this->writeFunctionCallArgument(c, i, &tempVars, out, &samplerId));
2543 if (samplerId !=
NA) {
2549 this->writeWord(this->getType(c.type()), out);
2550 this->writeWord(
result, out);
2551 this->writeWord(*entry, out);
2552 for (
SpvId id : argumentIds) {
2553 this->writeWord(
id, out);
2556 this->copyBackTempVars(tempVars, out);
2560SpvId SPIRVCodeGenerator::castScalarToType(
SpvId inputExprId,
2561 const Type& inputType,
2562 const Type& outputType,
2563 OutputStream& out) {
2564 if (outputType.isFloat()) {
2565 return this->castScalarToFloat(inputExprId, inputType, outputType, out);
2567 if (outputType.isSigned()) {
2568 return this->castScalarToSignedInt(inputExprId, inputType, outputType, out);
2570 if (outputType.isUnsigned()) {
2571 return this->castScalarToUnsignedInt(inputExprId, inputType, outputType, out);
2573 if (outputType.isBoolean()) {
2574 return this->castScalarToBoolean(inputExprId, inputType, outputType, out);
2578 outputType.description());
2582SpvId SPIRVCodeGenerator::castScalarToFloat(
SpvId inputId,
const Type& inputType,
2583 const Type& outputType, OutputStream& out) {
2585 if (inputType.isFloat()) {
2591 if (inputType.isBoolean()) {
2596 inputId, oneID, zeroID, out);
2597 }
else if (inputType.isSigned()) {
2599 }
else if (inputType.isUnsigned()) {
2602 SkDEBUGFAILF(
"unsupported type for float typecast: %s", inputType.description().c_str());
2608SpvId SPIRVCodeGenerator::castScalarToSignedInt(
SpvId inputId,
const Type& inputType,
2609 const Type& outputType, OutputStream& out) {
2611 if (inputType.isSigned()) {
2617 if (inputType.isBoolean()) {
2622 inputId, oneID, zeroID, out);
2623 }
else if (inputType.isFloat()) {
2625 }
else if (inputType.isUnsigned()) {
2626 this->writeInstruction(
SpvOpBitcast, this->getType(outputType),
result, inputId, out);
2628 SkDEBUGFAILF(
"unsupported type for signed int typecast: %s",
2629 inputType.description().c_str());
2635SpvId SPIRVCodeGenerator::castScalarToUnsignedInt(
SpvId inputId,
const Type& inputType,
2636 const Type& outputType, OutputStream& out) {
2638 if (inputType.isUnsigned()) {
2644 if (inputType.isBoolean()) {
2649 inputId, oneID, zeroID, out);
2650 }
else if (inputType.isFloat()) {
2652 }
else if (inputType.isSigned()) {
2653 this->writeInstruction(
SpvOpBitcast, this->getType(outputType),
result, inputId, out);
2655 SkDEBUGFAILF(
"unsupported type for unsigned int typecast: %s",
2656 inputType.description().c_str());
2662SpvId SPIRVCodeGenerator::castScalarToBoolean(
SpvId inputId,
const Type& inputType,
2663 const Type& outputType, OutputStream& out) {
2665 if (inputType.isBoolean()) {
2671 if (inputType.isSigned()) {
2675 inputId, zeroID, out);
2676 }
else if (inputType.isUnsigned()) {
2680 inputId, zeroID, out);
2681 }
else if (inputType.isFloat()) {
2685 inputId, zeroID, out);
2687 SkDEBUGFAILF(
"unsupported type for boolean typecast: %s", inputType.description().c_str());
2693SpvId SPIRVCodeGenerator::writeMatrixCopy(
SpvId src,
const Type& srcType,
const Type& dstType,
2694 OutputStream& out) {
2697 SkASSERT(srcType.componentType().matches(dstType.componentType()));
2698 const Type& srcColumnType = srcType.componentType().toCompound(
fContext, srcType.rows(), 1);
2699 const Type& dstColumnType = dstType.componentType().toCompound(
fContext, dstType.rows(), 1);
2700 SkASSERT(dstType.componentType().isFloat());
2701 SpvId dstColumnTypeId = this->getType(dstColumnType);
2702 const SpvId zeroId = this->writeLiteral(0.0, dstType.componentType());
2703 const SpvId oneId = this->writeLiteral(1.0, dstType.componentType());
2706 for (
int i = 0; i < dstType.columns(); i++) {
2707 if (i < srcType.columns()) {
2709 SpvId srcColumn = this->writeOpCompositeExtract(srcColumnType, src, i, out);
2711 if (srcType.rows() == dstType.rows()) {
2713 dstColumn = srcColumn;
2715 else if (dstType.rows() > srcType.rows()) {
2718 values.push_back(srcColumn);
2719 for (
int j = srcType.rows(); j < dstType.rows(); ++j) {
2720 values.push_back((i == j) ? oneId : zeroId);
2722 dstColumn = this->writeOpCompositeConstruct(dstColumnType, values, out);
2726 dstColumn = this->nextId(&dstType);
2728 this->writeWord(dstColumnTypeId, out);
2729 this->writeWord(dstColumn, out);
2730 this->writeWord(srcColumn, out);
2731 this->writeWord(srcColumn, out);
2732 for (
int j = 0; j < dstType.rows(); j++) {
2733 this->writeWord(j, out);
2740 for (
int j = 0; j < dstType.rows(); ++j) {
2741 values.push_back((i == j) ? oneId : zeroId);
2743 columns.
push_back(this->writeOpCompositeConstruct(dstColumnType, values, out));
2747 return this->writeOpCompositeConstruct(dstType, columns, out);
2750void SPIRVCodeGenerator::addColumnEntry(
const Type& columnType,
2755 OutputStream& out) {
2758 if (currentColumn->
size() == rows) {
2760 SpvId columnId = this->writeOpCompositeConstruct(columnType, *currentColumn, out);
2762 currentColumn->
clear();
2766SpvId SPIRVCodeGenerator::writeMatrixConstructor(
const ConstructorCompound& c, OutputStream& out) {
2770 const Type& arg0Type = c.arguments()[0]->type();
2774 for (
const std::unique_ptr<Expression>& arg : c.arguments()) {
2775 arguments.
push_back(this->writeExpression(*arg, out));
2778 if (arguments.
size() == 1 && arg0Type.isVector()) {
2783 for (
int i = 0; i < 4; ++i) {
2784 v[i] = this->writeOpCompositeExtract(
type.componentType(), arguments[0], i, out);
2787 SpvId v0v1 = this->writeOpCompositeConstruct(vecType, {v[0], v[1]},
out);
2788 SpvId v2v3 = this->writeOpCompositeConstruct(vecType, {v[2], v[3]},
out);
2789 return this->writeOpCompositeConstruct(
type, {v0v1, v2v3},
out);
2792 int rows =
type.rows();
2798 for (
int i = 0; i < arguments.
size(); i++) {
2799 const Type& argType = c.arguments()[i]->type();
2800 if (currentColumn.
empty() && argType.isVector() && argType.columns() == rows) {
2803 }
else if (argType.columns() == 1) {
2805 this->addColumnEntry(columnType, ¤tColumn, &columnIds, rows, arguments[i], out);
2808 for (
int j = 0; j < argType.columns(); ++j) {
2809 SpvId swizzle = this->writeOpCompositeExtract(argType.componentType(),
2810 arguments[i], j, out);
2811 this->addColumnEntry(columnType, ¤tColumn, &columnIds, rows, swizzle, out);
2816 return this->writeOpCompositeConstruct(
type, columnIds, out);
2819SpvId SPIRVCodeGenerator::writeConstructorCompound(
const ConstructorCompound& c,
2820 OutputStream& out) {
2821 return c.type().isMatrix() ? this->writeMatrixConstructor(c, out)
2822 : this->writeVectorConstructor(c,
out);
2825SpvId SPIRVCodeGenerator::writeVectorConstructor(
const ConstructorCompound& c, OutputStream& out) {
2827 const Type& componentType =
type.componentType();
2831 for (
int i = 0; i < c.arguments().
size(); i++) {
2832 const Type& argType = c.arguments()[i]->type();
2833 SkASSERT(componentType.numberKind() == argType.componentType().numberKind());
2835 SpvId arg = this->writeExpression(*c.arguments()[i], out);
2836 if (argType.isMatrix()) {
2841 for (
int j = 0; j < 4; ++j) {
2842 arguments.
push_back(this->writeOpCompositeExtract(componentType, arg,
2843 j / 2, j % 2, out));
2845 }
else if (argType.isVector()) {
2849 for (
int j = 0; j < argType.columns(); j++) {
2850 arguments.
push_back(this->writeOpCompositeExtract(componentType, arg, j, out));
2857 return this->writeOpCompositeConstruct(
type, arguments, out);
2860SpvId SPIRVCodeGenerator::writeConstructorSplat(
const ConstructorSplat& c, OutputStream& out) {
2862 SpvId argument = this->writeExpression(*c.argument(), out);
2866 values.push_back_n(c.type().columns(), argument);
2867 return this->writeOpCompositeConstruct(c.type(), values, out);
2870SpvId SPIRVCodeGenerator::writeCompositeConstructor(
const AnyConstructor& c, OutputStream& out) {
2871 SkASSERT(c.type().isArray() || c.type().isStruct());
2872 auto ctorArgs = c.argumentSpan();
2875 for (
const std::unique_ptr<Expression>& arg : ctorArgs) {
2876 arguments.
push_back(this->writeExpression(*arg, out));
2879 return this->writeOpCompositeConstruct(c.type(), arguments, out);
2882SpvId SPIRVCodeGenerator::writeConstructorScalarCast(
const ConstructorScalarCast& c,
2883 OutputStream& out) {
2885 if (
type.componentType().numberKind() == c.argument()->type().componentType().numberKind()) {
2886 return this->writeExpression(*c.argument(), out);
2889 const Expression& ctorExpr = *c.argument();
2890 SpvId expressionId = this->writeExpression(ctorExpr, out);
2891 return this->castScalarToType(expressionId, ctorExpr.type(),
type, out);
2894SpvId SPIRVCodeGenerator::writeConstructorCompoundCast(
const ConstructorCompoundCast& c,
2895 OutputStream& out) {
2896 const Type& ctorType = c.type();
2897 const Type& argType = c.argument()->type();
2898 SkASSERT(ctorType.isVector() || ctorType.isMatrix());
2901 SpvId compositeId = this->writeExpression(*c.argument(), out);
2902 if (ctorType.componentType().numberKind() == argType.componentType().numberKind()) {
2907 if (ctorType.isMatrix()) {
2908 return this->writeMatrixCopy(compositeId, argType, ctorType, out);
2913 const Type& srcType = argType.componentType();
2914 const Type& dstType = ctorType.componentType();
2917 for (
int index = 0; index < argType.columns(); ++index) {
2918 SpvId componentId = this->writeOpCompositeExtract(srcType, compositeId, index, out);
2919 arguments.
push_back(this->castScalarToType(componentId, srcType, dstType, out));
2922 return this->writeOpCompositeConstruct(ctorType, arguments, out);
2925SpvId SPIRVCodeGenerator::writeConstructorDiagonalMatrix(
const ConstructorDiagonalMatrix& c,
2926 OutputStream& out) {
2929 SkASSERT(c.argument()->type().isScalar());
2932 SpvId diagonal = this->writeExpression(*c.argument(), out);
2941 for (
int column = 0; column <
type.columns(); column++) {
2942 for (
int row = 0; row <
type.rows(); row++) {
2943 arguments[row] = (row == column) ? diagonal : zeroId;
2945 columnIds.
push_back(this->writeOpCompositeConstruct(vecType, arguments, out));
2947 return this->writeOpCompositeConstruct(
type, columnIds, out);
2950SpvId SPIRVCodeGenerator::writeConstructorMatrixResize(
const ConstructorMatrixResize& c,
2951 OutputStream& out) {
2953 SpvId argument = this->writeExpression(*c.argument(), out);
2956 return this->writeMatrixCopy(argument, c.argument()->type(), c.type(), out);
2979 if (
flags.isUniform()) {
2985 if (
flags.isBuffer()) {
2994 if (
flags.isWorkgroup()) {
2997 return fallbackStorageClass;
3001 switch (expr.
kind()) {
3002 case Expression::Kind::kVariableReference: {
3004 if (var.
storage() != Variable::Storage::kGlobal) {
3009 case Expression::Kind::kFieldAccess:
3011 case Expression::Kind::kIndex:
3018TArray<SpvId> SPIRVCodeGenerator::getAccessChain(
const Expression& expr, OutputStream& out) {
3019 switch (expr.kind()) {
3020 case Expression::Kind::kIndex: {
3021 const IndexExpression& indexExpr = expr.as<IndexExpression>();
3022 if (indexExpr.base()->is<Swizzle>()) {
3029 TArray<SpvId> chain = this->getAccessChain(*indexExpr.base(), out);
3030 chain.
push_back(this->writeExpression(*indexExpr.index(), out));
3033 case Expression::Kind::kFieldAccess: {
3034 const FieldAccess& fieldExpr = expr.as<FieldAccess>();
3035 TArray<SpvId> chain = this->getAccessChain(*fieldExpr.base(), out);
3040 SpvId id = this->getLValue(expr, out)->getPointer();
3054 , fIsMemoryObject(isMemoryObject)
3056 , fPrecision(precision)
3057 , fStorageClass(storageClass) {}
3064 return fIsMemoryObject;
3068 return fStorageClass;
3072 return fGen.writeOpLoad(fType, fPrecision, fPointer, out);
3076 if (!fIsMemoryObject) {
3082 fGen.fStoreCache.reset();
3085 fGen.writeOpStore(fStorageClass, fPointer,
value, out);
3090 const SpvId fPointer;
3091 const bool fIsMemoryObject;
3093 const SPIRVCodeGenerator::Precision fPrecision;
3102 , fVecPointer(vecPointer)
3103 , fComponents(components)
3104 , fBaseType(&baseType)
3105 , fSwizzleType(&swizzleType)
3106 , fStorageClass(storageClass) {}
3110 for (int8_t component : components) {
3111 if (component < 0 || component >= fComponents.size()) {
3112 SkDEBUGFAILF(
"swizzle accessed nonexistent component %d", (
int)component);
3115 updatedSwizzle.
push_back(fComponents[component]);
3117 fComponents = updatedSwizzle;
3118 fSwizzleType = &newType;
3123 return fStorageClass;
3128 fGen.writeInstruction(
SpvOpLoad, fGen.getType(*fBaseType),
base, fVecPointer, out);
3131 fGen.writeWord(fGen.getType(*fSwizzleType), out);
3132 fGen.writeWord(
result, out);
3133 fGen.writeWord(
base, out);
3134 fGen.writeWord(
base, out);
3135 for (
int component : fComponents) {
3136 fGen.writeWord(component, out);
3153 fGen.writeInstruction(
SpvOpLoad, fGen.getType(*fBaseType),
base, fVecPointer, out);
3154 SpvId shuffle = fGen.nextId(fBaseType);
3156 fGen.writeWord(fGen.getType(*fBaseType), out);
3157 fGen.writeWord(shuffle, out);
3158 fGen.writeWord(
base, out);
3159 fGen.writeWord(
value, out);
3160 for (
int i = 0; i < fBaseType->columns(); i++) {
3165 for (
int j = 0; j < fComponents.size(); j++) {
3166 if (fComponents[j] == i) {
3170 offset = (
int) (j + fBaseType->columns());
3174 fGen.writeWord(
offset, out);
3176 fGen.writeOpStore(fStorageClass, fVecPointer, shuffle, out);
3181 const SpvId fVecPointer;
3183 const Type* fBaseType;
3184 const Type* fSwizzleType;
3188int SPIRVCodeGenerator::findUniformFieldIndex(
const Variable& var)
const {
3189 int* fieldIndex = fTopLevelUniformMap.find(&var);
3190 return fieldIndex ? *fieldIndex : -1;
3193std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(
const Expression& expr,
3194 OutputStream& out) {
3196 Precision precision =
type.highPrecision() ? Precision::kDefault : Precision::kRelaxed;
3197 switch (expr.kind()) {
3198 case Expression::Kind::kVariableReference: {
3199 const Variable& var = *expr.as<VariableReference>().variable();
3200 int uniformIdx = this->findUniformFieldIndex(var);
3201 if (uniformIdx >= 0) {
3203 SpvId memberId = this->nextId(
nullptr);
3206 this->writeInstruction(
SpvOpAccessChain, typeId, memberId, fUniformBufferId,
3208 return std::make_unique<PointerLValue>(
3217 SpvId* entry = fVariableMap.find(&var);
3218 SkASSERTF(entry,
"%s", expr.description().c_str());
3229 SpvId accessId = this->nextId(
nullptr);
3230 SpvId typeId = this->getPointerType(
type, storageClass);
3232 this->writeInstruction(
SpvOpAccessChain, typeId, accessId, *entry, indexId, out);
3233 return std::make_unique<PointerLValue>(*
this,
3236 this->getType(
type),
3241 SpvId typeId = this->getType(
type, var.layout(), this->memoryLayoutForVariable(var));
3242 return std::make_unique<PointerLValue>(*
this, *entry,
3246 case Expression::Kind::kIndex:
3247 case Expression::Kind::kFieldAccess: {
3249 SpvId member = this->nextId(
nullptr);
3252 this->writeWord(this->getPointerType(
type, storageClass), out);
3253 this->writeWord(member, out);
3254 for (
SpvId idx : chain) {
3255 this->writeWord(idx, out);
3257 return std::make_unique<PointerLValue>(
3263 this->memoryLayoutForStorageClass(storageClass)),
3267 case Expression::Kind::kSwizzle: {
3268 const Swizzle& swizzle = expr.as<Swizzle>();
3269 std::unique_ptr<LValue> lvalue = this->getLValue(*swizzle.base(), out);
3270 if (lvalue->applySwizzle(swizzle.components(),
type)) {
3276 "unable to retrieve lvalue from swizzle");
3279 if (swizzle.components().size() == 1) {
3280 SpvId member = this->nextId(
nullptr);
3281 SpvId typeId = this->getPointerType(
type, storageClass);
3284 return std::make_unique<PointerLValue>(*
this, member,
3286 this->getType(
type),
3287 precision, storageClass);
3289 return std::make_unique<SwizzleLValue>(*
this,
base, swizzle.components(),
3290 swizzle.base()->type(),
type, storageClass);
3308 return std::make_unique<PointerLValue>(*
this,
result,
true,
3309 this->getType(
type), precision,
3315std::unique_ptr<Expression> SPIRVCodeGenerator::identifier(std::string_view
name) {
3316 std::unique_ptr<Expression> expr =
3318 return expr ? std::move(expr)
3322SpvId SPIRVCodeGenerator::writeVariableReference(
const VariableReference& ref, OutputStream& out) {
3323 const Variable* variable = ref.variable();
3324 switch (variable->layout().fBuiltin) {
3329 return this->getLValue(*this->identifier(
"sk_FragCoord"), out)->load(out);
3335 return this->getLValue(*this->identifier(
"sk_Clockwise"), out)->load(out);
3341 "sk_SecondaryFragColor is not allowed in SPIR-V");
3346 return this->getLValue(*this->identifier(
"sk_FragCoord"), out)->load(out);
3350 this->addRTFlipUniform(ref.fPosition);
3355 static constexpr char DEVICE_COORDS_NAME[] =
"$device_FragCoords";
3368 Variable::Storage::kGlobal);
3371 std::unique_ptr<Expression> deviceCoord = this->identifier(DEVICE_COORDS_NAME);
3380 SpvId flippedY = this->writeBinaryExpression(
3386 flippedY = this->writeBinaryExpression(
3393 {deviceCoordX, flippedY, deviceCoordZW},
3398 return this->getLValue(*this->identifier(
"sk_Clockwise"), out)->load(out);
3402 this->addRTFlipUniform(ref.fPosition);
3406 static constexpr char DEVICE_CLOCKWISE_NAME[] =
"$device_Clockwise";
3416 DEVICE_CLOCKWISE_NAME,
3419 Variable::Storage::kGlobal);
3429 SpvId positiveRTFlip = this->writeBinaryExpression(
3435 std::unique_ptr<Expression> deviceClockwise = this->identifier(DEVICE_CLOCKWISE_NAME);
3436 SpvId deviceClockwiseID = this->writeExpression(*deviceClockwise, out);
3437 return this->writeBinaryExpression(
3445 return this->writeExpression(*expr, out);
3454 if (fUseTextureSamplerPairs && variable->type().isSampler()) {
3455 if (
const auto* p = fSynthesizedSamplerMap.find(variable)) {
3456 SpvId* imgPtr = fVariableMap.find((*p)->fTexture.get());
3457 SpvId* samplerPtr = fVariableMap.find((*p)->fSampler.get());
3461 SpvId img = this->writeOpLoad(this->getType((*p)->fTexture->type()),
3462 Precision::kDefault, *imgPtr, out);
3463 SpvId sampler = this->writeOpLoad(this->getType((*p)->fSampler->type()),
3464 Precision::kDefault,
3469 this->getType(variable->type()),
3476 SkDEBUGFAIL(
"sampler missing from fSynthesizedSamplerMap");
3478 return this->getLValue(ref, out)->load(out);
3483SpvId SPIRVCodeGenerator::writeIndexExpression(
const IndexExpression& expr, OutputStream& out) {
3484 if (expr.base()->type().isVector()) {
3485 SpvId base = this->writeExpression(*expr.base(), out);
3486 SpvId index = this->writeExpression(*expr.index(), out);
3492 return getLValue(expr, out)->load(out);
3495SpvId SPIRVCodeGenerator::writeFieldAccess(
const FieldAccess& f, OutputStream& out) {
3496 return getLValue(f, out)->load(out);
3499SpvId SPIRVCodeGenerator::writeSwizzle(
const Expression& baseExpr,
3501 OutputStream& out) {
3502 size_t count = components.size();
3504 SpvId base = this->writeExpression(baseExpr, out);
3506 return this->writeOpCompositeExtract(
type,
base, components[0], out);
3511 this->writeWord(this->getType(
type), out);
3512 this->writeWord(
result, out);
3513 this->writeWord(
base, out);
3514 this->writeWord(
base, out);
3515 for (
int component : components) {
3516 this->writeWord(component, out);
3521SpvId SPIRVCodeGenerator::writeSwizzle(
const Swizzle& swizzle, OutputStream& out) {
3522 return this->writeSwizzle(*swizzle.base(), swizzle.components(), out);
3525SpvId SPIRVCodeGenerator::writeBinaryOperation(
const Type& resultType,
3533 "unsupported operand for binary expression: " + operandType.description());
3536 this->writeInstruction(op, this->getType(resultType),
result, lhs, rhs, out);
3541 OutputStream& out) {
3542 if (operandType.isVector()) {
3550SpvId SPIRVCodeGenerator::writeMatrixComparison(
const Type& operandType,
SpvId lhs,
SpvId rhs,
3553 OutputStream& out) {
3554 SpvOp_ compareOp =
is_float(operandType) ? floatOperator : intOperator;
3556 const Type& columnType = operandType.componentType().toCompound(
fContext,
3564 for (
int i = 0; i < operandType.columns(); i++) {
3565 SpvId columnL = this->writeOpCompositeExtract(columnType, lhs, i, out);
3566 SpvId columnR = this->writeOpCompositeExtract(columnType, rhs, i, out);
3568 this->writeInstruction(compareOp, bvecType,
compare, columnL, columnR, out);
3570 this->writeInstruction(vectorMergeOperator, boolType,
merge,
compare, out);
3573 this->writeInstruction(mergeOperator, boolType,
next,
result,
merge, out);
3582SpvId SPIRVCodeGenerator::writeComponentwiseMatrixUnary(
const Type& operandType,
3585 OutputStream& out) {
3587 const Type& columnType = operandType.columnType(
fContext);
3588 SpvId columnTypeId = this->getType(columnType);
3591 for (
int i = 0; i < operandType.columns(); i++) {
3592 SpvId srcColumn = this->writeOpCompositeExtract(columnType, operand, i, out);
3593 SpvId dstColumn = this->nextId(&operandType);
3594 this->writeInstruction(op, columnTypeId, dstColumn, srcColumn, out);
3598 return this->writeOpCompositeConstruct(operandType, columns, out);
3601SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(
const Type& operandType,
SpvId lhs,
3604 const Type& columnType = operandType.columnType(
fContext);
3605 SpvId columnTypeId = this->getType(columnType);
3608 for (
int i = 0; i < operandType.columns(); i++) {
3609 SpvId columnL = this->writeOpCompositeExtract(columnType, lhs, i, out);
3610 SpvId columnR = this->writeOpCompositeExtract(columnType, rhs, i, out);
3611 columns.
push_back(this->nextId(&operandType));
3612 this->writeInstruction(op, columnTypeId, columns[i], columnL, columnR, out);
3614 return this->writeOpCompositeConstruct(operandType, columns, out);
3617SpvId SPIRVCodeGenerator::writeReciprocal(
const Type&
type,
SpvId value, OutputStream& out) {
3619 SpvId one = this->writeLiteral(1.0,
type);
3621 this->writeInstruction(
SpvOpFDiv, this->getType(
type), reciprocal, one, value, out);
3625SpvId SPIRVCodeGenerator::writeScalarToMatrixSplat(
const Type& matrixType,
3627 OutputStream& out) {
3629 const Type& vectorType = matrixType.columnType(
fContext);
3631 vecArguments.
push_back_n(matrixType.rows(), scalarId);
3632 SpvId vectorId = this->writeOpCompositeConstruct(vectorType, vecArguments, out);
3636 matArguments.
push_back_n(matrixType.columns(), vectorId);
3637 return this->writeOpCompositeConstruct(matrixType, matArguments, out);
3644 return (
a.typeKind() ==
b.typeKind()) &&
3645 (
a.isScalar() ||
a.isVector() ||
a.isMatrix()) &&
3646 (
a.columns() ==
b.columns() &&
a.rows() ==
b.rows()) &&
3647 a.componentType().numberKind() ==
b.componentType().numberKind();
3650SpvId SPIRVCodeGenerator::writeDecomposedMatrixVectorMultiply(
const Type& leftType,
3652 const Type& rightType,
3654 const Type& resultType,
3655 OutputStream& out) {
3657 const Type& columnType = leftType.columnType(
fContext);
3658 const Type& scalarType = rightType.componentType();
3660 for (
int n = 0; n < leftType.rows(); ++n) {
3662 SpvId matN = this->writeOpCompositeExtract(columnType, lhs, n, out);
3665 SpvId vecN = this->writeOpCompositeExtract(scalarType, rhs, n, out);
3677 columnType, product,
3685SpvId SPIRVCodeGenerator::writeBinaryExpression(
const Type& leftType,
SpvId lhs, Operator op,
3687 const Type& resultType, OutputStream& out) {
3689 if (op.kind() == Operator::Kind::COMMA) {
3693 const Type* operandType;
3695 operandType = &leftType;
3699 if (leftType.isVector() && rightType.isNumber()) {
3700 if (resultType.componentType().isFloat()) {
3701 switch (op.kind()) {
3702 case Operator::Kind::SLASH: {
3703 rhs = this->writeReciprocal(rightType, rhs, out);
3706 case Operator::Kind::STAR: {
3719 rhs = this->writeOpCompositeConstruct(leftType, arguments, out);
3720 operandType = &leftType;
3721 }
else if (rightType.isVector() && leftType.isNumber()) {
3722 if (resultType.componentType().isFloat()) {
3723 if (op.kind() == Operator::Kind::STAR) {
3733 lhs = this->writeOpCompositeConstruct(rightType, arguments, out);
3734 operandType = &rightType;
3735 }
else if (leftType.isMatrix()) {
3736 if (op.kind() == Operator::Kind::STAR) {
3740 rightType.isVector() &&
3741 !resultType.highPrecision()) {
3742 return this->writeDecomposedMatrixVectorMultiply(leftType, lhs, rightType, rhs,
3748 if (rightType.isMatrix()) {
3750 }
else if (rightType.isVector()) {
3757 this->writeInstruction(spvop, this->getType(resultType),
result, lhs, rhs, out);
3765 SpvId rhsMatrix = this->writeScalarToMatrixSplat(leftType, rhs, out);
3768 return this->writeBinaryExpression(leftType, lhs, op, leftType, rhsMatrix,
3771 }
else if (rightType.isMatrix()) {
3772 if (op.kind() == Operator::Kind::STAR) {
3775 if (leftType.isVector()) {
3790 SpvId lhsMatrix = this->writeScalarToMatrixSplat(rightType, lhs, out);
3793 return this->writeBinaryExpression(rightType, lhsMatrix, op, rightType, rhs,
3802 switch (op.kind()) {
3803 case Operator::Kind::EQEQ: {
3804 if (operandType->isMatrix()) {
3805 return this->writeMatrixComparison(*operandType, lhs, rhs,
SpvOpFOrdEqual,
3808 if (operandType->isStruct()) {
3809 return this->writeStructComparison(*operandType, lhs, op, rhs, out);
3811 if (operandType->isArray()) {
3812 return this->writeArrayComparison(*operandType, lhs, op, rhs, out);
3815 const Type* tmpType;
3816 if (operandType->isVector()) {
3818 operandType->columns(),
3819 operandType->rows());
3821 tmpType = &resultType;
3827 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
3832 case Operator::Kind::NEQ:
3833 if (operandType->isMatrix()) {
3837 if (operandType->isStruct()) {
3838 return this->writeStructComparison(*operandType, lhs, op, rhs, out);
3840 if (operandType->isArray()) {
3841 return this->writeArrayComparison(*operandType, lhs, op, rhs, out);
3844 case Operator::Kind::LOGICALXOR:
3846 const Type* tmpType;
3847 if (operandType->isVector()) {
3849 operandType->columns(),
3850 operandType->rows());
3852 tmpType = &resultType;
3858 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
3863 case Operator::Kind::GT:
3865 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
3868 case Operator::Kind::LT:
3870 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpFOrdLessThan,
3872 case Operator::Kind::GTEQ:
3874 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
3877 case Operator::Kind::LTEQ:
3879 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
3882 case Operator::Kind::PLUS:
3883 if (leftType.isMatrix() && rightType.isMatrix()) {
3884 SkASSERT(leftType.matches(rightType));
3885 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
SpvOpFAdd, out);
3887 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpFAdd,
3889 case Operator::Kind::MINUS:
3890 if (leftType.isMatrix() && rightType.isMatrix()) {
3891 SkASSERT(leftType.matches(rightType));
3892 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
SpvOpFSub, out);
3894 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpFSub,
3896 case Operator::Kind::STAR:
3897 if (leftType.isMatrix() && rightType.isMatrix()) {
3904 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpFMul,
3906 case Operator::Kind::SLASH:
3907 if (leftType.isMatrix() && rightType.isMatrix()) {
3908 SkASSERT(leftType.matches(rightType));
3909 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
SpvOpFDiv, out);
3911 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpFDiv,
3913 case Operator::Kind::PERCENT:
3914 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpFMod,
3916 case Operator::Kind::SHL:
3917 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpUndef,
3920 case Operator::Kind::SHR:
3921 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpUndef,
3924 case Operator::Kind::BITWISEAND:
3925 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpUndef,
3927 case Operator::Kind::BITWISEOR:
3928 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpUndef,
3930 case Operator::Kind::BITWISEXOR:
3931 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
SpvOpUndef,
3939SpvId SPIRVCodeGenerator::writeArrayComparison(
const Type& arrayType,
SpvId lhs, Operator op,
3940 SpvId rhs, OutputStream& out) {
3942 SkASSERT(op.kind() == Operator::Kind::EQEQ || op.kind() == Operator::Kind::NEQ);
3944 const Type& componentType = arrayType.componentType();
3945 const int arraySize = arrayType.columns();
3951 for (
int index = 0; index < arraySize; ++index) {
3953 SpvId itemL = this->writeOpCompositeExtract(componentType, lhs, index, out);
3954 SpvId itemR = this->writeOpCompositeExtract(componentType, rhs, index, out);
3956 SpvId comparison = this->writeBinaryExpression(componentType, itemL, op,
3957 componentType, itemR, boolType, out);
3959 allComparisons = this->mergeComparisons(comparison, allComparisons, op, out);
3961 return allComparisons;
3964SpvId SPIRVCodeGenerator::writeStructComparison(
const Type& structType,
SpvId lhs, Operator op,
3965 SpvId rhs, OutputStream& out) {
3967 SkASSERT(op.kind() == Operator::Kind::EQEQ || op.kind() == Operator::Kind::NEQ);
3975 for (
int index = 0; index < (
int)fields.
size(); ++index) {
3977 const Type& fieldType = *fields[index].fType;
3979 SpvId fieldL = this->writeOpCompositeExtract(fieldType, lhs, index, out);
3980 SpvId fieldR = this->writeOpCompositeExtract(fieldType, rhs, index, out);
3982 SpvId comparison = this->writeBinaryExpression(fieldType, fieldL, op, fieldType, fieldR,
3985 allComparisons = this->mergeComparisons(comparison, allComparisons, op, out);
3987 return allComparisons;
3990SpvId SPIRVCodeGenerator::mergeComparisons(
SpvId comparison,
SpvId allComparisons, Operator op,
3991 OutputStream& out) {
3993 if (allComparisons ==
NA) {
3998 SpvId boolTypeId = this->getType(boolType);
3999 SpvId logicalOp = this->nextId(&boolType);
4000 switch (op.kind()) {
4001 case Operator::Kind::EQEQ:
4003 comparison, allComparisons, out);
4005 case Operator::Kind::NEQ:
4007 comparison, allComparisons, out);
4010 SkDEBUGFAILF(
"mergeComparisons only supports == and !=, not %s", op.operatorName());
4016SpvId SPIRVCodeGenerator::writeBinaryExpression(
const BinaryExpression&
b, OutputStream& out) {
4017 const Expression*
left =
b.left().get();
4018 const Expression*
right =
b.right().get();
4019 Operator op =
b.getOperator();
4021 switch (op.kind()) {
4022 case Operator::Kind::EQ: {
4024 SpvId rhs = this->writeExpression(*
right, out);
4025 this->getLValue(*
left, out)->store(rhs, out);
4028 case Operator::Kind::LOGICALAND:
4030 return this->writeLogicalAnd(*
b.left(), *
b.right(), out);
4032 case Operator::Kind::LOGICALOR:
4034 return this->writeLogicalOr(*
b.left(), *
b.right(), out);
4040 std::unique_ptr<LValue> lvalue;
4042 if (op.isAssignment()) {
4043 lvalue = this->getLValue(*
left, out);
4044 lhs = lvalue->load(out);
4047 lhs = this->writeExpression(*
left, out);
4050 SpvId rhs = this->writeExpression(*
right, out);
4051 SpvId result = this->writeBinaryExpression(
left->type(), lhs, op.removeAssignment(),
4052 right->type(), rhs,
b.type(), out);
4054 lvalue->store(
result, out);
4059SpvId SPIRVCodeGenerator::writeLogicalAnd(
const Expression&
left,
const Expression&
right,
4060 OutputStream& out) {
4062 SpvId lhs = this->writeExpression(
left, out);
4064 ConditionalOpCounts conditionalOps = this->getConditionalOpCounts();
4066 SpvId rhsLabel = this->nextId(
nullptr);
4068 SpvId lhsBlock = fCurrentBlock;
4071 this->writeLabel(rhsLabel, kBranchIsOnPreviousLine, out);
4072 SpvId rhs = this->writeExpression(
right, out);
4073 SpvId rhsBlock = fCurrentBlock;
4075 this->writeLabel(
end, kBranchIsAbove, conditionalOps, out);
4078 lhsBlock, rhs, rhsBlock, out);
4083SpvId SPIRVCodeGenerator::writeLogicalOr(
const Expression&
left,
const Expression&
right,
4084 OutputStream& out) {
4086 SpvId lhs = this->writeExpression(
left, out);
4088 ConditionalOpCounts conditionalOps = this->getConditionalOpCounts();
4090 SpvId rhsLabel = this->nextId(
nullptr);
4092 SpvId lhsBlock = fCurrentBlock;
4095 this->writeLabel(rhsLabel, kBranchIsOnPreviousLine, out);
4096 SpvId rhs = this->writeExpression(
right, out);
4097 SpvId rhsBlock = fCurrentBlock;
4099 this->writeLabel(
end, kBranchIsAbove, conditionalOps, out);
4102 lhsBlock, rhs, rhsBlock, out);
4107SpvId SPIRVCodeGenerator::writeTernaryExpression(
const TernaryExpression& t, OutputStream& out) {
4109 SpvId test = this->writeExpression(*t.test(), out);
4110 if (t.ifTrue()->type().columns() == 1 &&
4115 SpvId trueId = this->writeExpression(*t.ifTrue(), out);
4116 SpvId falseId = this->writeExpression(*t.ifFalse(), out);
4122 ConditionalOpCounts conditionalOps = this->getConditionalOpCounts();
4126 SpvId var = this->nextId(
nullptr);
4129 SpvId trueLabel = this->nextId(
nullptr);
4130 SpvId falseLabel = this->nextId(
nullptr);
4134 this->writeLabel(trueLabel, kBranchIsOnPreviousLine, out);
4137 this->writeLabel(falseLabel, kBranchIsAbove, conditionalOps, out);
4140 this->writeLabel(
end, kBranchIsAbove, conditionalOps, out);
4147SpvId SPIRVCodeGenerator::writePrefixExpression(
const PrefixExpression& p, OutputStream& out) {
4149 if (
p.getOperator().kind() == Operator::Kind::MINUS) {
4152 SpvId expr = this->writeExpression(*
p.operand(), out);
4153 if (
type.isMatrix()) {
4154 return this->writeComponentwiseMatrixUnary(
type, expr, negateOp, out);
4158 this->writeInstruction(negateOp, typeId,
result, expr, out);
4161 switch (
p.getOperator().kind()) {
4162 case Operator::Kind::PLUS:
4163 return this->writeExpression(*
p.operand(), out);
4164 case Operator::Kind::PLUSPLUS: {
4165 std::unique_ptr<LValue> lv = this->getLValue(*
p.operand(), out);
4166 SpvId one = this->writeLiteral(1.0,
type);
4173 case Operator::Kind::MINUSMINUS: {
4174 std::unique_ptr<LValue> lv = this->getLValue(*
p.operand(), out);
4175 SpvId one = this->writeLiteral(1.0,
type);
4181 case Operator::Kind::LOGICALNOT: {
4182 SkASSERT(
p.operand()->type().isBoolean());
4185 this->writeExpression(*
p.operand(), out), out);
4188 case Operator::Kind::BITWISENOT: {
4191 this->writeExpression(*
p.operand(), out), out);
4201SpvId SPIRVCodeGenerator::writePostfixExpression(
const PostfixExpression& p, OutputStream& out) {
4203 std::unique_ptr<LValue> lv = this->getLValue(*
p.operand(), out);
4205 SpvId one = this->writeLiteral(1.0,
type);
4206 switch (
p.getOperator().kind()) {
4207 case Operator::Kind::PLUSPLUS: {
4210 lv->store(temp, out);
4213 case Operator::Kind::MINUSMINUS: {
4216 lv->store(temp, out);
4226SpvId SPIRVCodeGenerator::writeLiteral(
const Literal& l) {
4227 return this->writeLiteral(l.value(), l.type());
4230SpvId SPIRVCodeGenerator::writeLiteral(
double value,
const Type&
type) {
4231 switch (
type.numberKind()) {
4233 float floatVal =
value;
4235 memcpy(&valueBits, &floatVal,
sizeof(valueBits));
4236 return this->writeOpConstant(
type, valueBits);
4239 return value ? this->writeOpConstantTrue(
type)
4240 : this->writeOpConstantFalse(
type);
4248SpvId SPIRVCodeGenerator::writeFunctionStart(
const FunctionDeclaration& f, OutputStream& out) {
4250 SpvId returnTypeId = this->getType(
f.returnType());
4251 SpvId functionTypeId = this->getFunctionType(f);
4254 std::string mangledName =
f.mangledName();
4257 std::string_view(mangledName.c_str(), mangledName.size()),
4259 for (
const Variable* parameter :
f.parameters()) {
4260 if (fUseTextureSamplerPairs && parameter->type().isSampler()) {
4261 auto [
texture, sampler] = this->synthesizeTextureAndSampler(*parameter);
4263 SpvId textureId = this->nextId(
nullptr);
4264 SpvId samplerId = this->nextId(
nullptr);
4265 fVariableMap.set(
texture, textureId);
4266 fVariableMap.set(sampler, samplerId);
4274 SpvId id = this->nextId(
nullptr);
4275 fVariableMap.set(parameter,
id);
4277 SpvId type = this->getFunctionParameterType(parameter->type(), parameter->layout());
4284SpvId SPIRVCodeGenerator::writeFunction(
const FunctionDefinition& f, OutputStream& out) {
4285 ConditionalOpCounts conditionalOps = this->getConditionalOpCounts();
4287 fVariableBuffer.
reset();
4288 SpvId result = this->writeFunctionStart(
f.declaration(), out);
4290 this->writeLabel(this->nextId(
nullptr), kBranchlessBlock, out);
4291 StringStream bodyBuffer;
4292 this->writeBlock(
f.body()->as<
Block>(), bodyBuffer);
4294 if (
f.declaration().isMain()) {
4298 if (fCurrentBlock) {
4299 if (
f.declaration().returnType().isVoid()) {
4306 this->pruneConditionalOps(conditionalOps);
4310void SPIRVCodeGenerator::writeLayout(
const Layout& layout,
SpvId target, Position
pos) {
4312 if (layout.fLocation >= 0) {
4316 if (layout.fBinding >= 0) {
4317 if (isPushConstant) {
4324 if (layout.fIndex >= 0) {
4328 if (layout.fSet >= 0) {
4329 if (isPushConstant) {
4336 if (layout.fInputAttachmentIndex >= 0) {
4338 layout.fInputAttachmentIndex, fDecorationBuffer);
4347void SPIRVCodeGenerator::writeFieldLayout(
const Layout& layout,
SpvId target,
int member) {
4351 if (layout.fLocation >= 0) {
4353 layout.fLocation, fDecorationBuffer);
4355 if (layout.fIndex >= 0) {
4357 layout.fIndex, fDecorationBuffer);
4359 if (layout.fInputAttachmentIndex >= 0) {
4361 layout.fInputAttachmentIndex, fDecorationBuffer);
4363 if (layout.fBuiltin >= 0) {
4365 layout.fBuiltin, fDecorationBuffer);
4369MemoryLayout SPIRVCodeGenerator::memoryLayoutForStorageClass(
SpvStorageClass_ storageClass) {
4371 : fDefaultMemoryLayout;
4374MemoryLayout SPIRVCodeGenerator::memoryLayoutForVariable(
const Variable& v)
const {
4377 : fDefaultMemoryLayout;
4380SpvId SPIRVCodeGenerator::writeInterfaceBlock(
const InterfaceBlock& intf,
bool appendRTFlip) {
4381 MemoryLayout memoryLayout = this->memoryLayoutForVariable(*intf.var());
4383 const Variable& intfVar = *intf.var();
4385 if (!memoryLayout.isSupported(
type)) {
4387 "' is not permitted here");
4388 return this->nextId(
nullptr);
4393 !fWroteRTFlip &&
type.isStruct()) {
4400 fields.emplace_back(Position(),
4422 intfVar.modifiersPosition(),
4424 intfVar.modifierFlags(),
4428 intfVar.isBuiltin(),
4429 intfVar.storage()));
4430 InterfaceBlock modifiedCopy(intf.fPosition, modifiedVar);
4431 result = this->writeInterfaceBlock(modifiedCopy,
false);
4433 Position(), modifiedVar, rtFlipStructType->fields().size() - 1));
4435 fVariableMap.set(&intfVar,
result);
4436 fWroteRTFlip =
true;
4440 if (intfVar.layout().fBuiltin == -1) {
4447 bool isStorageBuffer = intfVar.modifierFlags().isBuffer();
4453 SpvId ptrType = this->nextId(
nullptr);
4454 this->writeInstruction(
SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
4456 Layout layout = intfVar.layout();
4460 this->writeLayout(layout,
result, intfVar.fPosition);
4461 fVariableMap.set(&intfVar,
result);
4482bool SPIRVCodeGenerator::writeGlobalVarDeclaration(
ProgramKind kind,
4483 const VarDeclaration& varDecl) {
4484 const Variable* var = varDecl.var();
4488 if (backendFlags & ~kPermittedBackendFlags) {
4503 fTopLevelUniforms.push_back(&varDecl);
4507 if (fUseTextureSamplerPairs && var->type().isSampler()) {
4508 if (var->layout().fTexture == -1 || var->layout().fSampler == -1) {
4510 "and sampler indices");
4515 auto [
texture, sampler] = this->synthesizeTextureAndSampler(*var);
4516 this->writeGlobalVar(kind, storageClass, *
texture);
4517 this->writeGlobalVar(kind, storageClass, *sampler);
4522 SpvId id = this->writeGlobalVar(kind, storageClass, *var);
4523 if (
id !=
NA && varDecl.value()) {
4526 SpvId value = this->writeExpression(*varDecl.value(), fGlobalInitializersBuffer);
4527 this->writeOpStore(storageClass,
id, value, fGlobalInitializersBuffer);
4535 const Variable& var) {
4536 Layout layout = var.layout();
4537 const ModifierFlags
flags = var.modifierFlags();
4539 switch (layout.fBuiltin) {
4558 fVariableMap.set(&var,
id);
4564 SpvId typeId = this->getPointerType(*
type,
4566 this->memoryLayoutForStorageClass(storageClass),
4568 this->writeInstruction(
SpvOpVariable, typeId,
id, storageClass, fConstantBuffer);
4569 this->writeInstruction(
SpvOpName,
id, var.name(), fNameBuffer);
4570 this->writeLayout(layout,
id, var.fPosition);
4578 if (
flags.isWriteOnly()) {
4580 }
else if (
flags.isReadOnly()) {
4587void SPIRVCodeGenerator::writeVarDeclaration(
const VarDeclaration& varDecl, OutputStream& out) {
4594 const Variable* var = varDecl.var();
4595 SpvId id = this->nextId(&var->type());
4596 fVariableMap.set(var,
id);
4599 this->writeInstruction(
SpvOpName,
id, var->name(), fNameBuffer);
4600 if (varDecl.value()) {
4601 SpvId value = this->writeExpression(*varDecl.value(), out);
4606void SPIRVCodeGenerator::writeStatement(
const Statement&
s, OutputStream& out) {
4608 case Statement::Kind::kNop:
4610 case Statement::Kind::kBlock:
4611 this->writeBlock(
s.as<
Block>(), out);
4613 case Statement::Kind::kExpression:
4614 this->writeExpression(*
s.as<ExpressionStatement>().expression(), out);
4616 case Statement::Kind::kReturn:
4617 this->writeReturnStatement(
s.as<ReturnStatement>(), out);
4619 case Statement::Kind::kVarDeclaration:
4620 this->writeVarDeclaration(
s.as<VarDeclaration>(), out);
4622 case Statement::Kind::kIf:
4623 this->writeIfStatement(
s.as<IfStatement>(), out);
4625 case Statement::Kind::kFor:
4626 this->writeForStatement(
s.as<ForStatement>(), out);
4628 case Statement::Kind::kDo:
4629 this->writeDoStatement(
s.as<DoStatement>(), out);
4631 case Statement::Kind::kSwitch:
4632 this->writeSwitchStatement(
s.as<SwitchStatement>(), out);
4634 case Statement::Kind::kBreak:
4637 case Statement::Kind::kContinue:
4640 case Statement::Kind::kDiscard:
4644 SkDEBUGFAILF(
"unsupported statement: %s",
s.description().c_str());
4649void SPIRVCodeGenerator::writeBlock(
const Block&
b, OutputStream& out) {
4650 for (
const std::unique_ptr<Statement>& stmt :
b.children()) {
4651 this->writeStatement(*stmt, out);
4655SPIRVCodeGenerator::ConditionalOpCounts SPIRVCodeGenerator::getConditionalOpCounts() {
4656 return {fReachableOps.
size(), fStoreOps.
size()};
4659void SPIRVCodeGenerator::pruneConditionalOps(ConditionalOpCounts
ops) {
4661 while (fReachableOps.
size() >
ops.numReachableOps) {
4662 SpvId prunableSpvId = fReachableOps.
back();
4663 const Instruction* prunableOp = fSpvIdCache.
find(prunableSpvId);
4666 fOpCache.remove(*prunableOp);
4667 fSpvIdCache.
remove(prunableSpvId);
4669 SkDEBUGFAIL(
"reachable-op list contains unrecognized SpvId");
4676 while (fStoreOps.
size() >
ops.numStoreOps) {
4677 if (fStoreCache.
find(fStoreOps.
back())) {
4684void SPIRVCodeGenerator::writeIfStatement(
const IfStatement& stmt, OutputStream& out) {
4685 SpvId test = this->writeExpression(*stmt.test(), out);
4686 SpvId ifTrue = this->nextId(
nullptr);
4687 SpvId ifFalse = this->nextId(
nullptr);
4689 ConditionalOpCounts conditionalOps = this->getConditionalOpCounts();
4691 if (stmt.ifFalse()) {
4695 this->writeLabel(ifTrue, kBranchIsOnPreviousLine, out);
4696 this->writeStatement(*stmt.ifTrue(), out);
4697 if (fCurrentBlock) {
4700 this->writeLabel(ifFalse, kBranchIsAbove, conditionalOps, out);
4701 this->writeStatement(*stmt.ifFalse(), out);
4702 if (fCurrentBlock) {
4705 this->writeLabel(
end, kBranchIsAbove, conditionalOps, out);
4709 this->writeLabel(ifTrue, kBranchIsOnPreviousLine, out);
4710 this->writeStatement(*stmt.ifTrue(), out);
4711 if (fCurrentBlock) {
4712 this->writeInstruction(
SpvOpBranch, ifFalse, out);
4714 this->writeLabel(ifFalse, kBranchIsAbove, conditionalOps, out);
4718void SPIRVCodeGenerator::writeForStatement(
const ForStatement& f, OutputStream& out) {
4719 if (
f.initializer()) {
4720 this->writeStatement(*
f.initializer(), out);
4723 ConditionalOpCounts conditionalOps = this->getConditionalOpCounts();
4731 SpvId body = this->nextId(
nullptr);
4737 this->writeLabel(
header, kBranchIsBelow, conditionalOps, out);
4740 this->writeLabel(
start, kBranchIsOnPreviousLine, out);
4742 SpvId test = this->writeExpression(*
f.test(), out);
4747 this->writeLabel(body, kBranchIsOnPreviousLine, out);
4748 this->writeStatement(*
f.statement(), out);
4749 if (fCurrentBlock) {
4752 this->writeLabel(
next, kBranchIsAbove, conditionalOps, out);
4754 this->writeExpression(*
f.next(), out);
4757 this->writeLabel(
end, kBranchIsAbove, conditionalOps, out);
4762void SPIRVCodeGenerator::writeDoStatement(
const DoStatement&
d, OutputStream& out) {
4763 ConditionalOpCounts conditionalOps = this->getConditionalOpCounts();
4772 SpvId continueTarget = this->nextId(
nullptr);
4773 fContinueTarget.
push_back(continueTarget);
4777 this->writeLabel(
header, kBranchIsBelow, conditionalOps, out);
4780 this->writeLabel(
start, kBranchIsOnPreviousLine, out);
4781 this->writeStatement(*
d.statement(), out);
4782 if (fCurrentBlock) {
4784 this->writeLabel(
next, kBranchIsOnPreviousLine, out);
4785 this->writeInstruction(
SpvOpBranch, continueTarget, out);
4787 this->writeLabel(continueTarget, kBranchIsAbove, conditionalOps, out);
4788 SpvId test = this->writeExpression(*
d.test(), out);
4790 this->writeLabel(
end, kBranchIsAbove, conditionalOps, out);
4795void SPIRVCodeGenerator::writeSwitchStatement(
const SwitchStatement&
s, OutputStream& out) {
4796 SpvId value = this->writeExpression(*
s.value(), out);
4798 ConditionalOpCounts conditionalOps = this->getConditionalOpCounts();
4810 for (
const std::unique_ptr<Statement>& stmt : cases) {
4811 const SwitchCase& c = stmt->as<SwitchCase>();
4812 SpvId label = this->nextId(
nullptr);
4814 if (!c.isDefault()) {
4817 defaultLabel = label;
4827 SkBitSet caseIsCollapsed(cases.size());
4828 for (
int index = cases.size() - 2; index >= 0; index--) {
4829 if (cases[index]->as<SwitchCase>().statement()->isEmpty()) {
4830 caseIsCollapsed.set(index);
4831 labels[index] = labels[index + 1];
4839 this->writeWord(value, out);
4840 this->writeWord(defaultLabel, out);
4841 for (
int i = 0; i < cases.size(); ++i) {
4842 const SwitchCase& c = cases[i]->as<SwitchCase>();
4843 if (c.isDefault()) {
4846 this->writeWord(c.value(), out);
4847 this->writeWord(labels[i], out);
4849 for (
int i = 0; i < cases.size(); ++i) {
4850 if (caseIsCollapsed.test(i)) {
4853 const SwitchCase& c = cases[i]->as<SwitchCase>();
4855 this->writeLabel(labels[i], kBranchIsOnPreviousLine, out);
4857 this->writeLabel(labels[i], kBranchIsAbove, conditionalOps, out);
4859 this->writeStatement(*c.statement(), out);
4860 if (fCurrentBlock) {
4861 this->writeInstruction(
SpvOpBranch, labels[i + 1], out);
4864 this->writeLabel(
end, kBranchIsAbove, conditionalOps, out);
4868void SPIRVCodeGenerator::writeReturnStatement(
const ReturnStatement& r, OutputStream& out) {
4869 if (r.expression()) {
4870 this->writeInstruction(
SpvOpReturnValue, this->writeExpression(*r.expression(), out),
4882SPIRVCodeGenerator::EntrypointAdapter SPIRVCodeGenerator::writeEntrypointAdapter(
4883 const FunctionDeclaration&
main) {
4891 const Symbol* skFragColorSymbol = symbolTable->find(
"sk_FragColor");
4893 const Variable& skFragColorVar = skFragColorSymbol->as<Variable>();
4894 auto skFragColorRef = std::make_unique<VariableReference>(Position(), &skFragColorVar,
4895 VariableReference::RefKind::kWrite);
4897 if (!
main.returnType().matches(skFragColorRef->type())) {
4899 main.returnType().description() +
"' from main()");
4902 ExpressionArray
args;
4903 if (
main.parameters().size() == 1) {
4906 "SPIR-V does not support parameter of type '" +
4907 main.parameters()[0]->type().description() +
"' to main()");
4910 double kZero[2] = {0.0, 0.0};
4914 auto callMainFn = std::make_unique<FunctionCall>(Position(), &
main.returnType(), &
main,
4918 auto assignmentStmt = std::make_unique<ExpressionStatement>(std::make_unique<BinaryExpression>(
4920 std::move(skFragColorRef),
4922 std::move(callMainFn),
4923 &
main.returnType()));
4927 entrypointStmts.
push_back(std::move(assignmentStmt));
4928 auto entrypointBlock = Block::Make(Position(), std::move(entrypointStmts),
4929 Block::Kind::kBracedScope,
nullptr);
4931 EntrypointAdapter adapter;
4932 adapter.entrypointDecl =
4933 std::make_unique<FunctionDeclaration>(
fContext,
4943 *adapter.entrypointDecl,
4944 std::move(entrypointBlock),
4947 adapter.entrypointDecl->setDefinition(adapter.entrypointDef.get());
4951void SPIRVCodeGenerator::writeUniformBuffer(SymbolTable* topLevelSymbolTable) {
4952 SkASSERT(!fTopLevelUniforms.empty());
4953 static constexpr char kUniformBufferName[] =
"_UniformBuffer";
4959 for (
const VarDeclaration* topLevelUniform : fTopLevelUniforms) {
4960 const Variable* var = topLevelUniform->var();
4961 fTopLevelUniformMap.set(var, (
int)fields.
size());
4963 fields.
emplace_back(var->fPosition, var->layout(),
flags, var->name(), &var->type());
4980 fUniformBuffer.fStruct.get(),
4984 Variable::Storage::kGlobal);
4987 fUniformBuffer.fInterfaceBlock =
4988 std::make_unique<InterfaceBlock>(Position(), fUniformBuffer.fInnerVariable.get());
4991 fUniformBufferId = this->writeInterfaceBlock(*fUniformBuffer.fInterfaceBlock);
4994void SPIRVCodeGenerator::addRTFlipUniform(Position
pos) {
5002 fWroteRTFlip =
true;
5019 std::string_view
name =
"sksl_synthetic_uniforms";
5022 bool usePushConstants =
fProgram.
fConfig->fSettings.fUsePushConstants;
5023 int binding = -1,
set = -1;
5024 if (!usePushConstants) {
5026 if (binding == -1) {
5051 Variable::Storage::kGlobal));
5055 std::make_unique<FieldSymbol>(Position(), intfVar, 0));
5057 InterfaceBlock intf(Position(), intfVar);
5058 this->writeInterfaceBlock(intf,
false);
5061std::tuple<const Variable*, const Variable*> SPIRVCodeGenerator::synthesizeTextureAndSampler(
5062 const Variable& combinedSampler) {
5066 auto data = std::make_unique<SynthesizedTextureSamplerPair>();
5068 Layout texLayout = combinedSampler.layout();
5069 texLayout.fBinding = texLayout.fTexture;
5070 data->fTextureName = std::string(combinedSampler.name()) +
"_texture";
5075 combinedSampler.modifierFlags(),
5076 &combinedSampler.type().textureType(),
5080 Variable::Storage::kGlobal);
5082 Layout samplerLayout = combinedSampler.layout();
5083 samplerLayout.fBinding = samplerLayout.fSampler;
5085 data->fSamplerName = std::string(combinedSampler.name()) +
"_sampler";
5090 combinedSampler.modifierFlags(),
5095 Variable::Storage::kGlobal);
5097 const Variable* t =
texture.get();
5098 const Variable*
s = sampler.get();
5100 data->fSampler = std::move(sampler);
5101 fSynthesizedSamplerMap.set(&combinedSampler, std::move(data));
5106void SPIRVCodeGenerator::writeInstructions(
const Program& program, OutputStream& out) {
5107 fGLSLExtendedInstructions = this->nextId(
nullptr);
5111 const FunctionDeclaration*
main =
nullptr;
5112 int localSizeX = 1, localSizeY = 1, localSizeZ = 1;
5113 Position combinedSamplerPos;
5114 Position separateSamplerPos;
5115 for (
const ProgramElement* e : program.elements()) {
5116 switch (
e->kind()) {
5117 case ProgramElement::Kind::kFunction: {
5119 const FunctionDefinition& funcDef =
e->as<FunctionDefinition>();
5120 const FunctionDeclaration& funcDecl = funcDef.declaration();
5121 fFunctionMap.set(&funcDecl, this->nextId(
nullptr));
5122 if (funcDecl.isMain()) {
5127 case ProgramElement::Kind::kGlobalVar: {
5131 const GlobalVarDeclaration& decl =
e->as<GlobalVarDeclaration>();
5132 const Variable& var = *decl.varDeclaration().var();
5133 if (var.type().isSampler()) {
5135 combinedSamplerPos = decl.position();
5138 separateSamplerPos = decl.position();
5143 case ProgramElement::Kind::kModifiers: {
5147 const ModifiersDeclaration& modifiers =
e->as<ModifiersDeclaration>();
5148 if (modifiers.layout().fLocalSizeX >= 0) {
5149 localSizeX = modifiers.layout().fLocalSizeX;
5151 if (modifiers.layout().fLocalSizeY >= 0) {
5152 localSizeY = modifiers.layout().fLocalSizeY;
5154 if (modifiers.layout().fLocalSizeZ >= 0) {
5155 localSizeZ = modifiers.layout().fLocalSizeZ;
5171 if (combinedSamplerPos.valid() && separateSamplerPos.valid()) {
5177 fUseTextureSamplerPairs = separateSamplerPos.valid();
5180 std::set<SpvId> interfaceVars;
5181 for (
const ProgramElement* e : program.elements()) {
5182 if (
e->is<InterfaceBlock>()) {
5183 const InterfaceBlock& intf =
e->as<InterfaceBlock>();
5184 SpvId id = this->writeInterfaceBlock(intf);
5187 intf.var()->layout().fBuiltin == -1) {
5188 interfaceVars.insert(
id);
5196 const VarDeclaration* missingClockwiseDecl =
nullptr;
5198 if (
const Symbol* clockwise = program.fSymbols->findBuiltinSymbol(
"sk_Clockwise")) {
5199 missingClockwiseDecl = clockwise->as<Variable>().varDeclaration();
5203 for (
const ProgramElement* e : program.elements()) {
5204 if (
e->is<GlobalVarDeclaration>()) {
5205 const VarDeclaration& decl =
e->as<GlobalVarDeclaration>().varDeclaration();
5206 if (!this->writeGlobalVarDeclaration(program.fConfig->fKind, decl)) {
5209 if (missingClockwiseDecl == &decl) {
5211 missingClockwiseDecl =
nullptr;
5217 if (missingClockwiseDecl) {
5218 if (!this->writeGlobalVarDeclaration(program.fConfig->fKind, *missingClockwiseDecl)) {
5221 missingClockwiseDecl =
nullptr;
5224 if (!fTopLevelUniforms.empty()) {
5229 EntrypointAdapter adapter;
5231 adapter = this->writeEntrypointAdapter(*
main);
5232 if (adapter.entrypointDecl) {
5233 fFunctionMap.set(adapter.entrypointDecl.get(), this->nextId(
nullptr));
5234 this->writeFunction(*adapter.entrypointDef, body);
5235 main = adapter.entrypointDecl.get();
5239 for (
const ProgramElement* e : program.elements()) {
5240 if (
e->is<FunctionDefinition>()) {
5241 this->writeFunction(
e->as<FunctionDefinition>(), body);
5245 for (
const auto& [var, spvId] : fVariableMap) {
5246 if (var->storage() == Variable::Storage::kGlobal &&
5248 interfaceVars.insert(spvId);
5251 this->writeCapabilities(out);
5252 this->writeInstruction(
SpvOpExtInstImport, fGLSLExtendedInstructions,
"GLSL.std.450", out);
5255 (
SpvId)(3 + (
main->name().length() + 4) / 4) + (int32_t)interfaceVars.size(),
5264 SK_ABORT(
"cannot write this kind of program to SPIR-V\n");
5267 this->writeWord(entryPoint, out);
5268 this->writeString(
main->name(), out);
5269 for (
int var : interfaceVars) {
5270 this->writeWord(var, out);
5281 localSizeX, localSizeY, localSizeZ,
5284 for (
const ProgramElement* e : program.elements()) {
5303 this->writeWord(fIdCount, *
fOut);
5304 this->writeWord(0, *
fOut);
5309#if defined(SK_ENABLE_SPIRV_VALIDATION)
5312 const uint32_t* programData =
reinterpret_cast<const uint32_t*
>(program.data());
5313 size_t programSize = program.size() / 4;
5315 spvtools::SpirvTools
tools(SPV_ENV_VULKAN_1_0);
5317 auto msgFn = [&errors](spv_message_level_t,
const char*,
const spv_position_t&,
const char* m) {
5318 errors +=
"SPIR-V validation error: ";
5322 tools.SetMessageConsumer(msgFn);
5327 bool result =
tools.Validate(programData, programSize);
5329#if defined(SKSL_STANDALONE)
5331 std::string disassembly;
5332 uint32_t
options = spvtools::SpirvTools::kDefaultDisassembleOption;
5333 options |= SPV_BINARY_TO_TEXT_OPTION_INDENT;
5334 if (
tools.Disassemble(programData, programSize, &disassembly,
options)) {
5335 errors.append(disassembly);
5351#ifdef SK_ENABLE_SPIRV_VALIDATION
5357 std::string_view binary =
buffer.str();
5359 out.write(binary.data(), binary.size());
5365 program.
fContext->fErrors->setSource(std::string_view());
static bool compare(const SkBitmap &ref, const SkIRect &iref, const SkBitmap &test, const SkIRect &itest)
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 std::unique_ptr< SkEncoder > Make(SkWStream *dst, const SkPixmap *src, const SkYUVAPixmaps *srcYUVA, const SkColorSpace *srcYUVAColorSpace, const SkJpegEncoder::Options &options)
static uint32_t hash(const SkShaderBase::GradientInfo &v)
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
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)
static constexpr bool SkToBool(const T &x)
Type::kYUV Type::kRGBA() int(0.7 *637)
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
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 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
static const uint8_t buffer[]
uint32_t uint32_t * format
Dart_NativeFunction function
uint32_t Hash32(const void *data, size_t bytes, uint32_t seed)
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)
skia_private::STArray< 4, int8_t > ComponentArray
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)
SkEnumBitMask< SkSL::LayoutFlag > LayoutFlags
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
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 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 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
#define TRACE_EVENT0(category_group, name)