blob: 646748e3879f81bcb489362fece3667fb70b9351 [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Ethan Nicholasbcf35f82017-03-30 18:42:48 +00007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Ethan Nicholas9bd301d2017-03-31 16:04:34 +00009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "src/sksl/GLSL.std.450.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070011
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "src/sksl/SkSLCompiler.h"
Brian Osman00185012021-02-04 16:07:11 -050013#include "src/sksl/SkSLOperators.h"
John Stiles4d6310a2021-01-26 19:58:22 -050014#include "src/sksl/ir/SkSLBlock.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/sksl/ir/SkSLExpressionStatement.h"
16#include "src/sksl/ir/SkSLExtension.h"
17#include "src/sksl/ir/SkSLIndexExpression.h"
18#include "src/sksl/ir/SkSLVariableReference.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070019
Ethan Nicholas0be34802019-08-15 12:36:58 -040020#ifdef SK_VULKAN
21#include "src/gpu/vk/GrVkCaps.h"
22#endif
23
John Stilescd806892021-01-06 13:33:31 -050024#define kLast_Capability SpvCapabilityMultiViewport
25
ethannicholasb3058bd2016-07-01 08:22:01 -070026namespace SkSL {
27
ethannicholasb3058bd2016-07-01 08:22:01 -070028static const int32_t SKSL_MAGIC = 0x0; // FIXME: we should probably register a magic number
29
30void SPIRVCodeGenerator::setupIntrinsics() {
31#define ALL_GLSL(x) std::make_tuple(kGLSL_STD_450_IntrinsicKind, GLSLstd450 ## x, GLSLstd450 ## x, \
32 GLSLstd450 ## x, GLSLstd450 ## x)
33#define BY_TYPE_GLSL(ifFloat, ifInt, ifUInt) std::make_tuple(kGLSL_STD_450_IntrinsicKind, \
34 GLSLstd450 ## ifFloat, \
35 GLSLstd450 ## ifInt, \
36 GLSLstd450 ## ifUInt, \
37 SpvOpUndef)
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040038#define ALL_SPIRV(x) std::make_tuple(kSPIRV_IntrinsicKind, SpvOp ## x, SpvOp ## x, SpvOp ## x, \
39 SpvOp ## x)
ethannicholasb3058bd2016-07-01 08:22:01 -070040#define SPECIAL(x) std::make_tuple(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic, \
41 k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
42 k ## x ## _SpecialIntrinsic)
Ethan Nicholas0df1b042017-03-31 13:56:23 -040043 fIntrinsicMap[String("round")] = ALL_GLSL(Round);
44 fIntrinsicMap[String("roundEven")] = ALL_GLSL(RoundEven);
45 fIntrinsicMap[String("trunc")] = ALL_GLSL(Trunc);
46 fIntrinsicMap[String("abs")] = BY_TYPE_GLSL(FAbs, SAbs, SAbs);
47 fIntrinsicMap[String("sign")] = BY_TYPE_GLSL(FSign, SSign, SSign);
48 fIntrinsicMap[String("floor")] = ALL_GLSL(Floor);
49 fIntrinsicMap[String("ceil")] = ALL_GLSL(Ceil);
50 fIntrinsicMap[String("fract")] = ALL_GLSL(Fract);
51 fIntrinsicMap[String("radians")] = ALL_GLSL(Radians);
52 fIntrinsicMap[String("degrees")] = ALL_GLSL(Degrees);
53 fIntrinsicMap[String("sin")] = ALL_GLSL(Sin);
54 fIntrinsicMap[String("cos")] = ALL_GLSL(Cos);
55 fIntrinsicMap[String("tan")] = ALL_GLSL(Tan);
56 fIntrinsicMap[String("asin")] = ALL_GLSL(Asin);
57 fIntrinsicMap[String("acos")] = ALL_GLSL(Acos);
58 fIntrinsicMap[String("atan")] = SPECIAL(Atan);
59 fIntrinsicMap[String("sinh")] = ALL_GLSL(Sinh);
60 fIntrinsicMap[String("cosh")] = ALL_GLSL(Cosh);
61 fIntrinsicMap[String("tanh")] = ALL_GLSL(Tanh);
62 fIntrinsicMap[String("asinh")] = ALL_GLSL(Asinh);
63 fIntrinsicMap[String("acosh")] = ALL_GLSL(Acosh);
64 fIntrinsicMap[String("atanh")] = ALL_GLSL(Atanh);
65 fIntrinsicMap[String("pow")] = ALL_GLSL(Pow);
66 fIntrinsicMap[String("exp")] = ALL_GLSL(Exp);
67 fIntrinsicMap[String("log")] = ALL_GLSL(Log);
68 fIntrinsicMap[String("exp2")] = ALL_GLSL(Exp2);
69 fIntrinsicMap[String("log2")] = ALL_GLSL(Log2);
70 fIntrinsicMap[String("sqrt")] = ALL_GLSL(Sqrt);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040071 fIntrinsicMap[String("inverse")] = ALL_GLSL(MatrixInverse);
John Stilesa07338f2020-12-17 12:39:08 -050072 fIntrinsicMap[String("outerProduct")] = ALL_SPIRV(OuterProduct);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040073 fIntrinsicMap[String("transpose")] = ALL_SPIRV(Transpose);
John Stiles3679cd12020-12-09 16:22:12 -050074 fIntrinsicMap[String("isinf")] = ALL_SPIRV(IsInf);
75 fIntrinsicMap[String("isnan")] = ALL_SPIRV(IsNan);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040076 fIntrinsicMap[String("inversesqrt")] = ALL_GLSL(InverseSqrt);
77 fIntrinsicMap[String("determinant")] = ALL_GLSL(Determinant);
Brian Osmand1b593f2020-12-28 13:00:46 -050078 fIntrinsicMap[String("matrixCompMult")] = SPECIAL(MatrixCompMult);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040079 fIntrinsicMap[String("matrixInverse")] = ALL_GLSL(MatrixInverse);
Ethan Nicholas70a44b22017-11-30 09:09:16 -050080 fIntrinsicMap[String("mod")] = SPECIAL(Mod);
John Stiles01957272020-12-09 17:14:47 -050081 fIntrinsicMap[String("modf")] = ALL_GLSL(Modf);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050082 fIntrinsicMap[String("min")] = SPECIAL(Min);
83 fIntrinsicMap[String("max")] = SPECIAL(Max);
84 fIntrinsicMap[String("clamp")] = SPECIAL(Clamp);
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040085 fIntrinsicMap[String("saturate")] = SPECIAL(Saturate);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040086 fIntrinsicMap[String("dot")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
Ethan Nicholas0187ae62017-05-03 11:03:44 -040087 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050088 fIntrinsicMap[String("mix")] = SPECIAL(Mix);
Brian Osman6ba3be12020-11-13 16:32:52 -050089 fIntrinsicMap[String("step")] = SPECIAL(Step);
90 fIntrinsicMap[String("smoothstep")] = SPECIAL(SmoothStep);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040091 fIntrinsicMap[String("fma")] = ALL_GLSL(Fma);
92 fIntrinsicMap[String("frexp")] = ALL_GLSL(Frexp);
93 fIntrinsicMap[String("ldexp")] = ALL_GLSL(Ldexp);
ethannicholasb3058bd2016-07-01 08:22:01 -070094
Ethan Nicholas0df1b042017-03-31 13:56:23 -040095#define PACK(type) fIntrinsicMap[String("pack" #type)] = ALL_GLSL(Pack ## type); \
96 fIntrinsicMap[String("unpack" #type)] = ALL_GLSL(Unpack ## type)
ethannicholasb3058bd2016-07-01 08:22:01 -070097 PACK(Snorm4x8);
98 PACK(Unorm4x8);
99 PACK(Snorm2x16);
100 PACK(Unorm2x16);
101 PACK(Half2x16);
102 PACK(Double2x32);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400103 fIntrinsicMap[String("length")] = ALL_GLSL(Length);
104 fIntrinsicMap[String("distance")] = ALL_GLSL(Distance);
105 fIntrinsicMap[String("cross")] = ALL_GLSL(Cross);
106 fIntrinsicMap[String("normalize")] = ALL_GLSL(Normalize);
John Stiles0d19fb42020-12-10 17:04:37 -0500107 fIntrinsicMap[String("faceforward")] = ALL_GLSL(FaceForward);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400108 fIntrinsicMap[String("reflect")] = ALL_GLSL(Reflect);
109 fIntrinsicMap[String("refract")] = ALL_GLSL(Refract);
John Stilese7dc7cb2020-12-22 15:37:14 -0500110 fIntrinsicMap[String("bitCount")] = ALL_SPIRV(BitCount);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400111 fIntrinsicMap[String("findLSB")] = ALL_GLSL(FindILsb);
112 fIntrinsicMap[String("findMSB")] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
113 fIntrinsicMap[String("dFdx")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400114 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700115 fIntrinsicMap[String("dFdy")] = SPECIAL(DFdy);
Chris Dalton09212192018-11-13 15:07:24 -0500116 fIntrinsicMap[String("fwidth")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFwidth,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400117 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400118 fIntrinsicMap[String("makeSampler2D")] = SPECIAL(SampledImage);
119
Ethan Nicholas13863662019-07-29 13:05:15 -0400120 fIntrinsicMap[String("sample")] = SPECIAL(Texture);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400121 fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
Greg Daniel64773e62016-11-22 09:44:03 -0500122
John Stilescc9ff002020-12-09 18:39:41 -0500123 fIntrinsicMap[String("floatBitsToInt")] = ALL_SPIRV(Bitcast);
124 fIntrinsicMap[String("floatBitsToUint")] = ALL_SPIRV(Bitcast);
125 fIntrinsicMap[String("intBitsToFloat")] = ALL_SPIRV(Bitcast);
126 fIntrinsicMap[String("uintBitsToFloat")] = ALL_SPIRV(Bitcast);
127
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400128 fIntrinsicMap[String("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400129 SpvOpUndef, SpvOpUndef, SpvOpAny);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400130 fIntrinsicMap[String("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400131 SpvOpUndef, SpvOpUndef, SpvOpAll);
Brian Osman540c13a2020-11-24 16:55:34 -0500132 fIntrinsicMap[String("not")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
133 SpvOpUndef, SpvOpUndef,
134 SpvOpLogicalNot);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400135 fIntrinsicMap[String("equal")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400136 SpvOpFOrdEqual, SpvOpIEqual,
137 SpvOpIEqual, SpvOpLogicalEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400138 fIntrinsicMap[String("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400139 SpvOpFOrdNotEqual, SpvOpINotEqual,
140 SpvOpINotEqual,
141 SpvOpLogicalNotEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400142 fIntrinsicMap[String("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500143 SpvOpFOrdLessThan, SpvOpSLessThan,
144 SpvOpULessThan, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400145 fIntrinsicMap[String("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500146 SpvOpFOrdLessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400147 SpvOpSLessThanEqual,
148 SpvOpULessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400149 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400150 fIntrinsicMap[String("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500151 SpvOpFOrdGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400152 SpvOpSGreaterThan,
153 SpvOpUGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400154 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400155 fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500156 SpvOpFOrdGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400157 SpvOpSGreaterThanEqual,
158 SpvOpUGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400159 SpvOpUndef);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400160 fIntrinsicMap[String("EmitVertex")] = ALL_SPIRV(EmitVertex);
161 fIntrinsicMap[String("EndPrimitive")] = ALL_SPIRV(EndPrimitive);
ethannicholasb3058bd2016-07-01 08:22:01 -0700162// interpolateAt* not yet supported...
163}
164
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400165void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700166 out.write((const char*) &word, sizeof(word));
ethannicholasb3058bd2016-07-01 08:22:01 -0700167}
168
ethannicholasd598f792016-07-25 10:08:54 -0700169static bool is_float(const Context& context, const Type& type) {
John Stiles4c151702021-02-09 18:31:34 -0500170 return (type.isScalar() || type.isVector() || type.isMatrix()) &&
171 type.componentType().isFloat();
ethannicholasb3058bd2016-07-01 08:22:01 -0700172}
173
ethannicholasd598f792016-07-25 10:08:54 -0700174static bool is_signed(const Context& context, const Type& type) {
John Stiles4c151702021-02-09 18:31:34 -0500175 return type.isEnum() ||
176 ((type.isScalar() || type.isVector()) && type.componentType().isSigned());
ethannicholasb3058bd2016-07-01 08:22:01 -0700177}
178
ethannicholasd598f792016-07-25 10:08:54 -0700179static bool is_unsigned(const Context& context, const Type& type) {
John Stiles4c151702021-02-09 18:31:34 -0500180 return (type.isScalar() || type.isVector()) && type.componentType().isUnsigned();
ethannicholasb3058bd2016-07-01 08:22:01 -0700181}
182
ethannicholasd598f792016-07-25 10:08:54 -0700183static bool is_bool(const Context& context, const Type& type) {
John Stiles4c151702021-02-09 18:31:34 -0500184 return (type.isScalar() || type.isVector()) && type.componentType().isBoolean();
ethannicholasb3058bd2016-07-01 08:22:01 -0700185}
186
ethannicholasd598f792016-07-25 10:08:54 -0700187static bool is_out(const Variable& var) {
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400188 return (var.modifiers().fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700189}
190
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400191void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400192 SkASSERT(opCode != SpvOpLoad || &out != &fConstantBuffer);
193 SkASSERT(opCode != SpvOpUndef);
ethannicholasb3058bd2016-07-01 08:22:01 -0700194 switch (opCode) {
195 case SpvOpReturn: // fall through
196 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700197 case SpvOpKill: // fall through
Ethan Nicholas7fb39362020-12-16 15:25:19 -0500198 case SpvOpSwitch: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700199 case SpvOpBranch: // fall through
200 case SpvOpBranchConditional:
John Stiles7142e402021-02-23 12:28:18 -0500201 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700202 fCurrentBlock = 0;
203 break;
204 case SpvOpConstant: // fall through
205 case SpvOpConstantTrue: // fall through
206 case SpvOpConstantFalse: // fall through
207 case SpvOpConstantComposite: // fall through
208 case SpvOpTypeVoid: // fall through
209 case SpvOpTypeInt: // fall through
210 case SpvOpTypeFloat: // fall through
211 case SpvOpTypeBool: // fall through
212 case SpvOpTypeVector: // fall through
213 case SpvOpTypeMatrix: // fall through
214 case SpvOpTypeArray: // fall through
215 case SpvOpTypePointer: // fall through
216 case SpvOpTypeFunction: // fall through
217 case SpvOpTypeRuntimeArray: // fall through
218 case SpvOpTypeStruct: // fall through
219 case SpvOpTypeImage: // fall through
220 case SpvOpTypeSampledImage: // fall through
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400221 case SpvOpTypeSampler: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700222 case SpvOpVariable: // fall through
223 case SpvOpFunction: // fall through
224 case SpvOpFunctionParameter: // fall through
225 case SpvOpFunctionEnd: // fall through
226 case SpvOpExecutionMode: // fall through
227 case SpvOpMemoryModel: // fall through
228 case SpvOpCapability: // fall through
229 case SpvOpExtInstImport: // fall through
230 case SpvOpEntryPoint: // fall through
231 case SpvOpSource: // fall through
232 case SpvOpSourceExtension: // fall through
233 case SpvOpName: // fall through
234 case SpvOpMemberName: // fall through
235 case SpvOpDecorate: // fall through
236 case SpvOpMemberDecorate:
237 break;
238 default:
John Stiles7142e402021-02-23 12:28:18 -0500239 if (!fProgram.fConfig->fSettings.fDeadCodeElimination) {
240 // When dead-code elimination is disabled, we may find ourselves with instructions
241 // that don't have an associated block. This should be a rare event, but if it
242 // happens, synthesize a label; this is necessary to satisfy the validator.
243 if (fCurrentBlock == 0) {
244 this->writeLabel(this->nextId(), out);
245 }
246 } else {
247 // When dead-code elimination is enabled, all code should be reachable and an
248 // associated block should already exist.
249 SkASSERT(fCurrentBlock);
250 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700251 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700252 this->writeWord((length << 16) | opCode, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700253}
254
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400255void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
Ethan Nicholas7fb39362020-12-16 15:25:19 -0500256 SkASSERT(!fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700257 fCurrentBlock = label;
258 this->writeInstruction(SpvOpLabel, label, out);
259}
260
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400261void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700262 this->writeOpCode(opCode, 1, out);
263}
264
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400265void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700266 this->writeOpCode(opCode, 2, out);
267 this->writeWord(word1, out);
268}
269
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700270void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputStream& out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400271 out.write(string, length);
ethannicholasb3058bd2016-07-01 08:22:01 -0700272 switch (length % 4) {
273 case 1:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500274 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400275 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700276 case 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500277 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400278 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700279 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500280 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700281 break;
282 default:
283 this->writeWord(0, out);
284 }
285}
286
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700287void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out) {
288 this->writeOpCode(opCode, 1 + (string.fLength + 4) / 4, out);
289 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700290}
291
292
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700293void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400294 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700295 this->writeOpCode(opCode, 2 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700296 this->writeWord(word1, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700297 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700298}
299
Greg Daniel64773e62016-11-22 09:44:03 -0500300void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700301 StringFragment string, OutputStream& out) {
302 this->writeOpCode(opCode, 3 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700303 this->writeWord(word1, out);
304 this->writeWord(word2, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700305 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700306}
307
Greg Daniel64773e62016-11-22 09:44:03 -0500308void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400309 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700310 this->writeOpCode(opCode, 3, out);
311 this->writeWord(word1, out);
312 this->writeWord(word2, out);
313}
314
Greg Daniel64773e62016-11-22 09:44:03 -0500315void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400316 int32_t word3, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700317 this->writeOpCode(opCode, 4, out);
318 this->writeWord(word1, out);
319 this->writeWord(word2, out);
320 this->writeWord(word3, out);
321}
322
Greg Daniel64773e62016-11-22 09:44:03 -0500323void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400324 int32_t word3, int32_t word4, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700325 this->writeOpCode(opCode, 5, out);
326 this->writeWord(word1, out);
327 this->writeWord(word2, out);
328 this->writeWord(word3, out);
329 this->writeWord(word4, out);
330}
331
Greg Daniel64773e62016-11-22 09:44:03 -0500332void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
333 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400334 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700335 this->writeOpCode(opCode, 6, out);
336 this->writeWord(word1, out);
337 this->writeWord(word2, out);
338 this->writeWord(word3, out);
339 this->writeWord(word4, out);
340 this->writeWord(word5, out);
341}
342
Greg Daniel64773e62016-11-22 09:44:03 -0500343void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700344 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400345 int32_t word6, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700346 this->writeOpCode(opCode, 7, out);
347 this->writeWord(word1, out);
348 this->writeWord(word2, out);
349 this->writeWord(word3, out);
350 this->writeWord(word4, out);
351 this->writeWord(word5, out);
352 this->writeWord(word6, out);
353}
354
Greg Daniel64773e62016-11-22 09:44:03 -0500355void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700356 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400357 int32_t word6, int32_t word7, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700358 this->writeOpCode(opCode, 8, out);
359 this->writeWord(word1, out);
360 this->writeWord(word2, out);
361 this->writeWord(word3, out);
362 this->writeWord(word4, out);
363 this->writeWord(word5, out);
364 this->writeWord(word6, out);
365 this->writeWord(word7, out);
366}
367
Greg Daniel64773e62016-11-22 09:44:03 -0500368void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700369 int32_t word3, int32_t word4, int32_t word5,
370 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400371 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700372 this->writeOpCode(opCode, 9, out);
373 this->writeWord(word1, out);
374 this->writeWord(word2, out);
375 this->writeWord(word3, out);
376 this->writeWord(word4, out);
377 this->writeWord(word5, out);
378 this->writeWord(word6, out);
379 this->writeWord(word7, out);
380 this->writeWord(word8, out);
381}
382
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400383void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700384 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
385 if (fCapabilities & bit) {
386 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
387 }
388 }
John Stiles270cec22021-02-17 12:59:36 -0500389 if (fProgram.fConfig->fKind == ProgramKind::kGeometry) {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400390 this->writeInstruction(SpvOpCapability, SpvCapabilityGeometry, out);
391 }
Ethan Nicholas81d15112018-07-13 12:48:50 -0400392 else {
393 this->writeInstruction(SpvOpCapability, SpvCapabilityShader, out);
394 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700395}
396
397SpvId SPIRVCodeGenerator::nextId() {
398 return fIdCount++;
399}
400
Ethan Nicholas19671772016-11-28 16:30:17 -0500401void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
402 SpvId resultId) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400403 this->writeInstruction(SpvOpName, resultId, String(type.name()).c_str(), fNameBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700404 // go ahead and write all of the field types, so we don't inadvertently write them while we're
405 // in the middle of writing the struct instruction
406 std::vector<SpvId> types;
407 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500408 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700409 }
410 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
411 this->writeWord(resultId, fConstantBuffer);
412 for (SpvId id : types) {
413 this->writeWord(id, fConstantBuffer);
414 }
415 size_t offset = 0;
416 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400417 const Type::Field& field = type.fields()[i];
John Stiles21f5f452020-11-30 09:57:59 -0500418 if (!MemoryLayout::LayoutIsSupported(*field.fType)) {
John Stiles0023c0c2020-11-16 13:32:18 -0500419 fErrors.error(type.fOffset, "type '" + field.fType->name() + "' is not permitted here");
420 return;
421 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400422 size_t size = memoryLayout.size(*field.fType);
423 size_t alignment = memoryLayout.alignment(*field.fType);
424 const Layout& fieldLayout = field.fModifiers.fLayout;
Ethan Nicholas19671772016-11-28 16:30:17 -0500425 if (fieldLayout.fOffset >= 0) {
Greg Danieldbd44c72017-01-24 15:12:12 -0500426 if (fieldLayout.fOffset < (int) offset) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700427 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400428 "offset of field '" + field.fName + "' must be at "
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500429 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -0500430 }
431 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700432 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400433 "offset of field '" + field.fName + "' must be a multiple"
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500434 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -0500435 }
436 offset = fieldLayout.fOffset;
437 } else {
438 size_t mod = offset % alignment;
439 if (mod) {
440 offset += alignment - mod;
441 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700442 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400443 this->writeInstruction(SpvOpMemberName, resultId, i, field.fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500444 this->writeLayout(fieldLayout, resultId, i);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400445 if (field.fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -0500446 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700447 (SpvId) offset, fDecorationBuffer);
448 }
John Stiles9aeed132020-11-24 17:36:06 -0500449 if (field.fType->isMatrix()) {
Greg Daniel64773e62016-11-22 09:44:03 -0500450 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -0700451 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500452 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400453 (SpvId) memoryLayout.stride(*field.fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800454 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700455 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400456 if (!field.fType->highPrecision()) {
457 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i,
458 SpvDecorationRelaxedPrecision, fDecorationBuffer);
459 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700460 offset += size;
John Stilesc0c51062020-12-03 17:16:29 -0500461 if ((field.fType->isArray() || field.fType->isStruct()) && offset % alignment != 0) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700462 offset += alignment - offset % alignment;
463 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700464 }
465}
466
Ethan Nicholase2c49992020-10-05 11:49:11 -0400467const Type& SPIRVCodeGenerator::getActualType(const Type& type) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500468 if (type.isFloat()) {
John Stiles54e7c052021-01-11 14:22:36 -0500469 return *fContext.fTypes.fFloat;
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400470 }
John Stiles4c151702021-02-09 18:31:34 -0500471 if (type.isSigned() || type.isEnum()) {
John Stiles54e7c052021-01-11 14:22:36 -0500472 return *fContext.fTypes.fInt;
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400473 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500474 if (type.isUnsigned()) {
John Stiles54e7c052021-01-11 14:22:36 -0500475 return *fContext.fTypes.fUInt;
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400476 }
John Stiles9aeed132020-11-24 17:36:06 -0500477 if (type.isMatrix() || type.isVector()) {
John Stiles54e7c052021-01-11 14:22:36 -0500478 if (type.componentType() == *fContext.fTypes.fHalf) {
479 return fContext.fTypes.fFloat->toCompound(fContext, type.columns(), type.rows());
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400480 }
John Stiles54e7c052021-01-11 14:22:36 -0500481 if (type.componentType() == *fContext.fTypes.fShort ||
482 type.componentType() == *fContext.fTypes.fByte) {
483 return fContext.fTypes.fInt->toCompound(fContext, type.columns(), type.rows());
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400484 }
John Stiles54e7c052021-01-11 14:22:36 -0500485 if (type.componentType() == *fContext.fTypes.fUShort ||
486 type.componentType() == *fContext.fTypes.fUByte) {
487 return fContext.fTypes.fUInt->toCompound(fContext, type.columns(), type.rows());
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400488 }
489 }
490 return type;
491}
492
ethannicholasb3058bd2016-07-01 08:22:01 -0700493SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800494 return this->getType(type, fDefaultLayout);
495}
496
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400497SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400498 const Type& type = this->getActualType(rawType);
Jim Van Verthf3ec9832020-10-21 16:09:57 -0400499 String key = type.name();
John Stilesc0c51062020-12-03 17:16:29 -0500500 if (type.isStruct() || type.isArray()) {
Jim Van Verthf3ec9832020-10-21 16:09:57 -0400501 key += to_string((int)layout.fStd);
Brian Osman2a4c0fb2021-01-22 13:41:40 -0500502#ifdef SK_DEBUG
503 SkASSERT(layout.fStd == MemoryLayout::Standard::k140_Standard ||
504 layout.fStd == MemoryLayout::Standard::k430_Standard);
505 MemoryLayout::Standard otherStd = layout.fStd == MemoryLayout::Standard::k140_Standard
506 ? MemoryLayout::Standard::k430_Standard
507 : MemoryLayout::Standard::k140_Standard;
508 String otherKey = type.name() + to_string((int)otherStd);
509 SkASSERT(fTypeMap.find(otherKey) == fTypeMap.end());
510#endif
Jim Van Verthf3ec9832020-10-21 16:09:57 -0400511 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800512 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700513 if (entry == fTypeMap.end()) {
514 SpvId result = this->nextId();
Ethan Nicholase6592142020-09-08 10:22:09 -0400515 switch (type.typeKind()) {
516 case Type::TypeKind::kScalar:
John Stiles4a7dc462020-11-25 11:08:08 -0500517 if (type.isBoolean()) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700518 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
John Stiles54e7c052021-01-11 14:22:36 -0500519 } else if (type == *fContext.fTypes.fInt || type == *fContext.fTypes.fShort ||
520 type == *fContext.fTypes.fIntLiteral) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700521 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
John Stiles54e7c052021-01-11 14:22:36 -0500522 } else if (type == *fContext.fTypes.fUInt || type == *fContext.fTypes.fUShort) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700523 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
John Stiles54e7c052021-01-11 14:22:36 -0500524 } else if (type == *fContext.fTypes.fFloat || type == *fContext.fTypes.fHalf ||
525 type == *fContext.fTypes.fFloatLiteral) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700526 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700527 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400528 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700529 }
530 break;
John Stilesfd41d872020-11-25 22:39:45 -0500531 case Type::TypeKind::kEnum:
532 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
533 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400534 case Type::TypeKind::kVector:
Greg Daniel64773e62016-11-22 09:44:03 -0500535 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800536 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700537 type.columns(), fConstantBuffer);
538 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400539 case Type::TypeKind::kMatrix:
Greg Daniel64773e62016-11-22 09:44:03 -0500540 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800541 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700542 type.columns(), fConstantBuffer);
543 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400544 case Type::TypeKind::kStruct:
ethannicholas8ac838d2016-11-22 08:39:36 -0800545 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700546 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400547 case Type::TypeKind::kArray: {
John Stiles21f5f452020-11-30 09:57:59 -0500548 if (!MemoryLayout::LayoutIsSupported(type)) {
549 fErrors.error(type.fOffset, "type '" + type.name() + "' is not permitted here");
550 return this->nextId();
551 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700552 if (type.columns() > 0) {
John Stilesb5db4822021-01-21 13:04:40 -0500553 SpvId typeId = this->getType(type.componentType(), layout);
554 IntLiteral countLiteral(fContext, /*offset=*/-1, type.columns());
555 SpvId countId = this->writeIntLiteral(countLiteral);
556 this->writeInstruction(SpvOpTypeArray, result, typeId, countId,
557 fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500558 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400559 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800560 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700561 } else {
John Stiles5570c512020-11-19 17:58:07 -0500562 // We shouldn't have any runtime-sized arrays right now
563 fErrors.error(type.fOffset, "runtime-sized arrays are not supported in SPIR-V");
Greg Daniel64773e62016-11-22 09:44:03 -0500564 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800565 this->getType(type.componentType(), layout),
566 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400567 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
568 (int32_t) layout.stride(type),
569 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700570 }
571 break;
572 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400573 case Type::TypeKind::kSampler: {
Greg Daniel64773e62016-11-22 09:44:03 -0500574 SpvId image = result;
575 if (SpvDimSubpassData != type.dimensions()) {
Stephen White792e2302019-08-09 13:33:51 -0400576 image = this->getType(type.textureType(), layout);
Greg Daniel64773e62016-11-22 09:44:03 -0500577 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400578 if (SpvDimBuffer == type.dimensions()) {
579 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
580 }
Greg Daniel64773e62016-11-22 09:44:03 -0500581 if (SpvDimSubpassData != type.dimensions()) {
582 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
583 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700584 break;
585 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400586 case Type::TypeKind::kSeparateSampler: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400587 this->writeInstruction(SpvOpTypeSampler, result, fConstantBuffer);
588 break;
589 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400590 case Type::TypeKind::kTexture: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400591 this->writeInstruction(SpvOpTypeImage, result,
John Stiles54e7c052021-01-11 14:22:36 -0500592 this->getType(*fContext.fTypes.fFloat, layout),
John Stilesc0c51062020-12-03 17:16:29 -0500593 type.dimensions(), type.isDepth(), type.isArrayedTexture(),
Stephen White792e2302019-08-09 13:33:51 -0400594 type.isMultisampled(), type.isSampled() ? 1 : 2,
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400595 SpvImageFormatUnknown, fConstantBuffer);
596 fImageTypeMap[key] = result;
597 break;
598 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700599 default:
John Stiles54e7c052021-01-11 14:22:36 -0500600 if (type == *fContext.fTypes.fVoid) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700601 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
602 } else {
John Stileseada7bc2021-02-02 16:29:32 -0500603 SkDEBUGFAILF("invalid type: %s", type.description().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -0700604 }
605 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800606 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700607 return result;
608 }
609 return entry->second;
610}
611
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400612SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400613 SkASSERT(type.typeKind() == Type::TypeKind::kSampler);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400614 this->getType(type);
615 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400616 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400617 return fImageTypeMap[key];
618}
619
ethannicholasd598f792016-07-25 10:08:54 -0700620SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400621 String key = to_string(this->getType(function.returnType())) + "(";
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400622 String separator;
Brian Osman5bf3e202020-10-13 10:34:18 -0400623 const std::vector<const Variable*>& parameters = function.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400624 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700625 key += separator;
626 separator = ", ";
Ethan Nicholased84b732020-10-08 11:45:44 -0400627 key += to_string(this->getType(parameters[i]->type()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700628 }
629 key += ")";
630 auto entry = fTypeMap.find(key);
631 if (entry == fTypeMap.end()) {
632 SpvId result = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -0400633 int32_t length = 3 + (int32_t) parameters.size();
634 SpvId returnType = this->getType(function.returnType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700635 std::vector<SpvId> parameterTypes;
Ethan Nicholased84b732020-10-08 11:45:44 -0400636 for (size_t i = 0; i < parameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500637 // glslang seems to treat all function arguments as pointers whether they need to be or
638 // not. I was initially puzzled by this until I ran bizarre failures with certain
639 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700640 // failure case:
641 //
642 // void sphere(float x) {
643 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500644 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700645 // void map() {
646 // sphere(1.0);
647 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500648 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700649 // void main() {
650 // for (int i = 0; i < 1; i++) {
651 // map();
652 // }
653 // }
654 //
Greg Daniel64773e62016-11-22 09:44:03 -0500655 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
656 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700657 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
658 // the spec makes this make sense.
659// if (is_out(function->fParameters[i])) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400660 parameterTypes.push_back(this->getPointerType(parameters[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -0700661 SpvStorageClassFunction));
662// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700663// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700664// }
665 }
666 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
667 this->writeWord(result, fConstantBuffer);
668 this->writeWord(returnType, fConstantBuffer);
669 for (SpvId id : parameterTypes) {
670 this->writeWord(id, fConstantBuffer);
671 }
672 fTypeMap[key] = result;
673 return result;
674 }
675 return entry->second;
676}
677
ethannicholas8ac838d2016-11-22 08:39:36 -0800678SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
679 return this->getPointerType(type, fDefaultLayout, storageClass);
680}
681
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400682SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700683 SpvStorageClass_ storageClass) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400684 const Type& type = this->getActualType(rawType);
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500685 String key = type.displayName() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700686 auto entry = fTypeMap.find(key);
687 if (entry == fTypeMap.end()) {
688 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500689 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700690 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700691 fTypeMap[key] = result;
692 return result;
693 }
694 return entry->second;
695}
696
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400697SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400698 switch (expr.kind()) {
699 case Expression::Kind::kBinary:
John Stiles81365af2020-08-18 09:24:00 -0400700 return this->writeBinaryExpression(expr.as<BinaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400701 case Expression::Kind::kBoolLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400702 return this->writeBoolLiteral(expr.as<BoolLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400703 case Expression::Kind::kConstructor:
John Stiles81365af2020-08-18 09:24:00 -0400704 return this->writeConstructor(expr.as<Constructor>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400705 case Expression::Kind::kIntLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400706 return this->writeIntLiteral(expr.as<IntLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400707 case Expression::Kind::kFieldAccess:
John Stiles81365af2020-08-18 09:24:00 -0400708 return this->writeFieldAccess(expr.as<FieldAccess>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400709 case Expression::Kind::kFloatLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400710 return this->writeFloatLiteral(expr.as<FloatLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400711 case Expression::Kind::kFunctionCall:
John Stiles81365af2020-08-18 09:24:00 -0400712 return this->writeFunctionCall(expr.as<FunctionCall>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400713 case Expression::Kind::kPrefix:
John Stiles81365af2020-08-18 09:24:00 -0400714 return this->writePrefixExpression(expr.as<PrefixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400715 case Expression::Kind::kPostfix:
John Stiles81365af2020-08-18 09:24:00 -0400716 return this->writePostfixExpression(expr.as<PostfixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400717 case Expression::Kind::kSwizzle:
John Stiles81365af2020-08-18 09:24:00 -0400718 return this->writeSwizzle(expr.as<Swizzle>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400719 case Expression::Kind::kVariableReference:
John Stiles81365af2020-08-18 09:24:00 -0400720 return this->writeVariableReference(expr.as<VariableReference>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400721 case Expression::Kind::kTernary:
John Stiles81365af2020-08-18 09:24:00 -0400722 return this->writeTernaryExpression(expr.as<TernaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400723 case Expression::Kind::kIndex:
John Stiles81365af2020-08-18 09:24:00 -0400724 return this->writeIndexExpression(expr.as<IndexExpression>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700725 default:
John Stileseada7bc2021-02-02 16:29:32 -0500726 SkDEBUGFAILF("unsupported expression: %s", expr.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500727 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700728 }
729 return -1;
730}
731
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400732SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400733 const FunctionDeclaration& function = c.function();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400734 auto intrinsic = fIntrinsicMap.find(function.name());
John Stiles93e661a2020-12-08 16:17:00 -0500735 if (intrinsic == fIntrinsicMap.end()) {
736 fErrors.error(c.fOffset, "unsupported intrinsic '" + function.description() + "'");
737 return -1;
738 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700739 int32_t intrinsicId;
John Stiles89ac7c22020-12-30 17:47:31 -0500740 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400741 if (arguments.size() > 0) {
742 const Type& type = arguments[0]->type();
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400743 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
744 intrinsicId = std::get<1>(intrinsic->second);
745 } else if (is_signed(fContext, type)) {
746 intrinsicId = std::get<2>(intrinsic->second);
747 } else if (is_unsigned(fContext, type)) {
748 intrinsicId = std::get<3>(intrinsic->second);
749 } else if (is_bool(fContext, type)) {
750 intrinsicId = std::get<4>(intrinsic->second);
751 } else {
752 intrinsicId = std::get<1>(intrinsic->second);
753 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700754 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400755 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700756 }
757 switch (std::get<0>(intrinsic->second)) {
758 case kGLSL_STD_450_IntrinsicKind: {
759 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400760 std::vector<SpvId> argumentIds;
761 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400762 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
John Stilesec241542021-02-11 17:50:09 -0500763 // TODO(skia:11052): swizzled lvalues won't work with getPointer()
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400764 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400765 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400766 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400767 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700768 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400769 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400770 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700771 this->writeWord(result, out);
772 this->writeWord(fGLSLExtendedInstructions, out);
773 this->writeWord(intrinsicId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400774 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700775 this->writeWord(id, out);
776 }
777 return result;
778 }
779 case kSPIRV_IntrinsicKind: {
Brian Osman46787d52020-11-24 14:18:23 -0500780 // GLSL supports dot(float, float), but SPIR-V does not. Convert it to FMul
John Stiles9aeed132020-11-24 17:36:06 -0500781 if (intrinsicId == SpvOpDot && arguments[0]->type().isScalar()) {
Brian Osman46787d52020-11-24 14:18:23 -0500782 intrinsicId = SpvOpFMul;
783 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700784 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400785 std::vector<SpvId> argumentIds;
786 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400787 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
John Stilesec241542021-02-11 17:50:09 -0500788 // TODO(skia:11052): swizzled lvalues won't work with getPointer()
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400789 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400790 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400791 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400792 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700793 }
John Stiles54e7c052021-01-11 14:22:36 -0500794 if (c.type() != *fContext.fTypes.fVoid) {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400795 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400796 this->writeWord(this->getType(c.type()), out);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400797 this->writeWord(result, out);
798 } else {
799 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
800 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400801 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700802 this->writeWord(id, out);
803 }
804 return result;
805 }
806 case kSpecial_IntrinsicKind:
807 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
808 default:
John Stiles93e661a2020-12-08 16:17:00 -0500809 fErrors.error(c.fOffset, "unsupported intrinsic '" + function.description() + "'");
810 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700811 }
812}
813
John Stiles8e3b6be2020-10-13 11:14:08 -0400814std::vector<SpvId> SPIRVCodeGenerator::vectorize(const ExpressionArray& args, OutputStream& out) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500815 int vectorSize = 0;
816 for (const auto& a : args) {
John Stiles9aeed132020-11-24 17:36:06 -0500817 if (a->type().isVector()) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500818 if (vectorSize) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400819 SkASSERT(a->type().columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500820 }
821 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400822 vectorSize = a->type().columns();
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500823 }
824 }
825 }
826 std::vector<SpvId> result;
John Stiles8e3b6be2020-10-13 11:14:08 -0400827 result.reserve(args.size());
Ethan Nicholas30d30222020-09-11 12:27:26 -0400828 for (const auto& arg : args) {
829 const Type& argType = arg->type();
830 SpvId raw = this->writeExpression(*arg, out);
John Stiles9aeed132020-11-24 17:36:06 -0500831 if (vectorSize && argType.isScalar()) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500832 SpvId vector = this->nextId();
833 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400834 this->writeWord(this->getType(argType.toCompound(fContext, vectorSize, 1)), out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500835 this->writeWord(vector, out);
836 for (int i = 0; i < vectorSize; i++) {
837 this->writeWord(raw, out);
838 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400839 this->writePrecisionModifier(argType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500840 result.push_back(vector);
841 } else {
842 result.push_back(raw);
843 }
844 }
845 return result;
846}
847
848void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
849 SpvId signedInst, SpvId unsignedInst,
850 const std::vector<SpvId>& args,
851 OutputStream& out) {
852 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
853 this->writeWord(this->getType(type), out);
854 this->writeWord(id, out);
855 this->writeWord(fGLSLExtendedInstructions, out);
856
857 if (is_float(fContext, type)) {
858 this->writeWord(floatInst, out);
859 } else if (is_signed(fContext, type)) {
860 this->writeWord(signedInst, out);
861 } else if (is_unsigned(fContext, type)) {
862 this->writeWord(unsignedInst, out);
863 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400864 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500865 }
866 for (SpvId a : args) {
867 this->writeWord(a, out);
868 }
869}
870
Greg Daniel64773e62016-11-22 09:44:03 -0500871SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400872 OutputStream& out) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400873 const ExpressionArray& arguments = c.arguments();
ethannicholasb3058bd2016-07-01 08:22:01 -0700874 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400875 const Type& callType = c.type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700876 switch (kind) {
877 case kAtan_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400878 std::vector<SpvId> argumentIds;
879 for (const std::unique_ptr<Expression>& arg : arguments) {
880 argumentIds.push_back(this->writeExpression(*arg, out));
ethannicholasb3058bd2016-07-01 08:22:01 -0700881 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400882 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400883 this->writeWord(this->getType(callType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700884 this->writeWord(result, out);
885 this->writeWord(fGLSLExtendedInstructions, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400886 this->writeWord(argumentIds.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
887 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700888 this->writeWord(id, out);
889 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400890 break;
891 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400892 case kSampledImage_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400893 SkASSERT(arguments.size() == 2);
894 SpvId img = this->writeExpression(*arguments[0], out);
895 SpvId sampler = this->writeExpression(*arguments[1], out);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400896 this->writeInstruction(SpvOpSampledImage,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400897 this->getType(callType),
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400898 result,
899 img,
900 sampler,
901 out);
902 break;
903 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400904 case kSubpassLoad_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400905 SpvId img = this->writeExpression(*arguments[0], out);
John Stiles8e3b6be2020-10-13 11:14:08 -0400906 ExpressionArray args;
John Stilesf4bda742020-10-14 16:57:41 -0400907 args.reserve_back(2);
John Stiles8e3b6be2020-10-13 11:14:08 -0400908 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
909 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
John Stiles54f00492021-02-19 11:46:10 -0500910 Constructor ctor(/*offset=*/-1, *fContext.fTypes.fInt2, std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400911 SpvId coords = this->writeConstantVector(ctor);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400912 if (arguments.size() == 1) {
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400913 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400914 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400915 result,
916 img,
917 coords,
918 out);
919 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400920 SkASSERT(arguments.size() == 2);
921 SpvId sample = this->writeExpression(*arguments[1], out);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400922 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400923 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400924 result,
925 img,
926 coords,
927 SpvImageOperandsSampleMask,
928 sample,
929 out);
930 }
931 break;
932 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700933 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500934 SpvOp_ op = SpvOpImageSampleImplicitLod;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400935 const Type& arg1Type = arguments[1]->type();
936 switch (arguments[0]->type().dimensions()) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500937 case SpvDim1D:
John Stiles54e7c052021-01-11 14:22:36 -0500938 if (arg1Type == *fContext.fTypes.fFloat2) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500939 op = SpvOpImageSampleProjImplicitLod;
940 } else {
John Stiles54e7c052021-01-11 14:22:36 -0500941 SkASSERT(arg1Type == *fContext.fTypes.fFloat);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500942 }
943 break;
944 case SpvDim2D:
John Stiles54e7c052021-01-11 14:22:36 -0500945 if (arg1Type == *fContext.fTypes.fFloat3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500946 op = SpvOpImageSampleProjImplicitLod;
947 } else {
John Stiles54e7c052021-01-11 14:22:36 -0500948 SkASSERT(arg1Type == *fContext.fTypes.fFloat2);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500949 }
950 break;
951 case SpvDim3D:
John Stiles54e7c052021-01-11 14:22:36 -0500952 if (arg1Type == *fContext.fTypes.fFloat4) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500953 op = SpvOpImageSampleProjImplicitLod;
954 } else {
John Stiles54e7c052021-01-11 14:22:36 -0500955 SkASSERT(arg1Type == *fContext.fTypes.fFloat3);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500956 }
957 break;
958 case SpvDimCube: // fall through
959 case SpvDimRect: // fall through
960 case SpvDimBuffer: // fall through
961 case SpvDimSubpassData:
962 break;
963 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400964 SpvId type = this->getType(callType);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400965 SpvId sampler = this->writeExpression(*arguments[0], out);
966 SpvId uv = this->writeExpression(*arguments[1], out);
967 if (arguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500968 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700969 SpvImageOperandsBiasMask,
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400970 this->writeExpression(*arguments[2], out),
ethannicholasb3058bd2016-07-01 08:22:01 -0700971 out);
972 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400973 SkASSERT(arguments.size() == 2);
John Stiles270cec22021-02-17 12:59:36 -0500974 if (fProgram.fConfig->fSettings.fSharpenTextures) {
Brian Osman8a83ca42018-02-12 14:32:17 -0500975 FloatLiteral lodBias(fContext, -1, -0.5);
976 this->writeInstruction(op, type, result, sampler, uv,
977 SpvImageOperandsBiasMask,
978 this->writeFloatLiteral(lodBias),
979 out);
980 } else {
981 this->writeInstruction(op, type, result, sampler, uv,
982 out);
983 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700984 }
985 break;
986 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500987 case kMod_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400988 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400989 SkASSERT(args.size() == 2);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400990 const Type& operandType = arguments[0]->type();
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500991 SpvOp_ op;
992 if (is_float(fContext, operandType)) {
993 op = SpvOpFMod;
994 } else if (is_signed(fContext, operandType)) {
995 op = SpvOpSMod;
996 } else if (is_unsigned(fContext, operandType)) {
997 op = SpvOpUMod;
998 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400999 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -05001000 return 0;
1001 }
1002 this->writeOpCode(op, 5, out);
1003 this->writeWord(this->getType(operandType), out);
1004 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001005 this->writeWord(args[0], out);
1006 this->writeWord(args[1], out);
1007 break;
1008 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -07001009 case kDFdy_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001010 SpvId fn = this->writeExpression(*arguments[0], out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -07001011 this->writeOpCode(SpvOpDPdy, 4, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001012 this->writeWord(this->getType(callType), out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -07001013 this->writeWord(result, out);
1014 this->writeWord(fn, out);
John Stiles270cec22021-02-17 12:59:36 -05001015 if (fProgram.fConfig->fSettings.fFlipY) {
Chris Daltonb8af5ad2019-02-25 14:54:21 -07001016 // Flipping Y also negates the Y derivatives.
1017 SpvId flipped = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001018 this->writeInstruction(SpvOpFNegate, this->getType(callType), flipped, result,
1019 out);
1020 this->writePrecisionModifier(callType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -07001021 return flipped;
1022 }
1023 break;
1024 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001025 case kClamp_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001026 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001027 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001028 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001029 GLSLstd450UClamp, args, out);
1030 break;
1031 }
1032 case kMax_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001033 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001034 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001035 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMax, GLSLstd450SMax,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001036 GLSLstd450UMax, args, out);
1037 break;
1038 }
1039 case kMin_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001040 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001041 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001042 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMin, GLSLstd450SMin,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001043 GLSLstd450UMin, args, out);
1044 break;
1045 }
1046 case kMix_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001047 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001048 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001049 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMix, SpvOpUndef,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001050 SpvOpUndef, args, out);
1051 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -05001052 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001053 case kSaturate_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001054 SkASSERT(arguments.size() == 1);
John Stiles8e3b6be2020-10-13 11:14:08 -04001055 ExpressionArray finalArgs;
John Stilesf4bda742020-10-14 16:57:41 -04001056 finalArgs.reserve_back(3);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001057 finalArgs.push_back(arguments[0]->clone());
John Stiles8e3b6be2020-10-13 11:14:08 -04001058 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1059 /*value=*/0));
1060 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1061 /*value=*/1));
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001062 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001063 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001064 GLSLstd450UClamp, spvArgs, out);
1065 break;
1066 }
Brian Osman6ba3be12020-11-13 16:32:52 -05001067 case kSmoothStep_SpecialIntrinsic: {
1068 std::vector<SpvId> args = this->vectorize(arguments, out);
1069 SkASSERT(args.size() == 3);
1070 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450SmoothStep, SpvOpUndef,
1071 SpvOpUndef, args, out);
1072 break;
1073 }
1074 case kStep_SpecialIntrinsic: {
1075 std::vector<SpvId> args = this->vectorize(arguments, out);
1076 SkASSERT(args.size() == 2);
1077 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450Step, SpvOpUndef,
1078 SpvOpUndef, args, out);
1079 break;
1080 }
Brian Osmand1b593f2020-12-28 13:00:46 -05001081 case kMatrixCompMult_SpecialIntrinsic: {
1082 SkASSERT(arguments.size() == 2);
1083 SpvId lhs = this->writeExpression(*arguments[0], out);
1084 SpvId rhs = this->writeExpression(*arguments[1], out);
1085 result = this->writeComponentwiseMatrixBinary(callType, lhs, rhs, SpvOpFMul, SpvOpUndef,
1086 out);
1087 break;
1088 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001089 }
1090 return result;
1091}
1092
John Stilesec241542021-02-11 17:50:09 -05001093namespace {
1094struct TempVar {
1095 SpvId spvId;
1096 const Type* type;
1097 std::unique_ptr<SPIRVCodeGenerator::LValue> lvalue;
1098};
1099}
1100
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001101SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001102 const FunctionDeclaration& function = c.function();
John Stiles89ac7c22020-12-30 17:47:31 -05001103 if (function.isBuiltin() && !function.definition()) {
1104 return this->writeIntrinsicCall(c, out);
1105 }
John Stiles8e3b6be2020-10-13 11:14:08 -04001106 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001107 const auto& entry = fFunctionMap.find(&function);
ethannicholasb3058bd2016-07-01 08:22:01 -07001108 if (entry == fFunctionMap.end()) {
John Stiles89ac7c22020-12-30 17:47:31 -05001109 fErrors.error(c.fOffset, "function '" + function.description() + "' is not defined");
1110 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001111 }
John Stilesec241542021-02-11 17:50:09 -05001112 // Temp variables are used to write back out-parameters after the function call is complete.
1113 std::vector<TempVar> tempVars;
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001114 std::vector<SpvId> argumentIds;
1115 for (size_t i = 0; i < arguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001116 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001117 // passed directly
1118 SpvId tmpVar;
1119 // if we need a temporary var to store this argument, this is the value to store in the var
1120 SpvId tmpValueId;
Ethan Nicholased84b732020-10-08 11:45:44 -04001121 if (is_out(*function.parameters()[i])) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001122 std::unique_ptr<LValue> lv = this->getLValue(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001123 SpvId ptr = lv->getPointer();
John Stilesec241542021-02-11 17:50:09 -05001124 if (ptr != (SpvId) -1) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001125 argumentIds.push_back(ptr);
ethannicholasb3058bd2016-07-01 08:22:01 -07001126 continue;
1127 } else {
1128 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1129 // copy it into a temp, call the function, read the value out of the temp, and then
1130 // update the lvalue.
1131 tmpValueId = lv->load(out);
1132 tmpVar = this->nextId();
John Stilesec241542021-02-11 17:50:09 -05001133 tempVars.push_back(TempVar{tmpVar, &arguments[i]->type(), std::move(lv)});
ethannicholasb3058bd2016-07-01 08:22:01 -07001134 }
1135 } else {
John Stilesec241542021-02-11 17:50:09 -05001136 // See getFunctionType for an explanation of why we're always using pointer parameters.
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001137 tmpValueId = this->writeExpression(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001138 tmpVar = this->nextId();
1139 }
Greg Daniel64773e62016-11-22 09:44:03 -05001140 this->writeInstruction(SpvOpVariable,
John Stilesec241542021-02-11 17:50:09 -05001141 this->getPointerType(arguments[i]->type(), SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001142 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001143 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001144 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001145 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001146 argumentIds.push_back(tmpVar);
ethannicholasb3058bd2016-07-01 08:22:01 -07001147 }
1148 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001149 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001150 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001151 this->writeWord(result, out);
1152 this->writeWord(entry->second, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001153 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001154 this->writeWord(id, out);
1155 }
John Stilesec241542021-02-11 17:50:09 -05001156 // Now that the call is complete, we copy temp out-variables back to their real lvalues.
1157 for (const TempVar& tempVar : tempVars) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001158 SpvId load = this->nextId();
John Stilesec241542021-02-11 17:50:09 -05001159 this->writeInstruction(SpvOpLoad, getType(*tempVar.type), load, tempVar.spvId, out);
1160 this->writePrecisionModifier(*tempVar.type, load);
1161 tempVar.lvalue->store(load, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001162 }
1163 return result;
1164}
1165
ethannicholasf789b382016-08-03 12:43:36 -07001166SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001167 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001168 SkASSERT(type.isVector() && c.isCompileTimeConstant());
John Stilescd806892021-01-06 13:33:31 -05001169
John Stiles9cfaa4f2021-01-06 17:52:00 -05001170 // Get each of the constructor components as SPIR-V constants.
John Stilescd806892021-01-06 13:33:31 -05001171 SPIRVVectorConstant key{this->getType(type),
1172 /*fValueId=*/{SpvId(-1), SpvId(-1), SpvId(-1), SpvId(-1)}};
John Stiles9cfaa4f2021-01-06 17:52:00 -05001173
1174 if (c.componentType().isFloat()) {
1175 for (int i = 0; i < type.columns(); i++) {
1176 FloatLiteral literal(c.fOffset, c.getFVecComponent(i), &c.componentType());
1177 key.fValueId[i] = this->writeFloatLiteral(literal);
1178 }
1179 } else if (c.componentType().isInteger()) {
1180 for (int i = 0; i < type.columns(); i++) {
1181 IntLiteral literal(c.fOffset, c.getIVecComponent(i), &c.componentType());
1182 key.fValueId[i] = this->writeIntLiteral(literal);
1183 }
1184 } else if (c.componentType().isBoolean()) {
1185 for (int i = 0; i < type.columns(); i++) {
1186 BoolLiteral literal(c.fOffset, c.getBVecComponent(i), &c.componentType());
1187 key.fValueId[i] = this->writeBoolLiteral(literal);
ethannicholasb3058bd2016-07-01 08:22:01 -07001188 }
1189 } else {
John Stiles9cfaa4f2021-01-06 17:52:00 -05001190 SkDEBUGFAILF("unexpected vector component type: %s",
1191 c.componentType().displayName().c_str());
1192 return SpvId(-1);
ethannicholasb3058bd2016-07-01 08:22:01 -07001193 }
John Stilescd806892021-01-06 13:33:31 -05001194
1195 // Check to see if we've already synthesized this vector constant.
1196 auto [iter, newlyCreated] = fVectorConstants.insert({key, (SpvId)-1});
1197 if (newlyCreated) {
1198 // Emit an OpConstantComposite instruction for this constant.
1199 SpvId result = this->nextId();
John Stiles9cfaa4f2021-01-06 17:52:00 -05001200 this->writeOpCode(SpvOpConstantComposite, 3 + type.columns(), fConstantBuffer);
John Stilescd806892021-01-06 13:33:31 -05001201 this->writeWord(key.fTypeId, fConstantBuffer);
1202 this->writeWord(result, fConstantBuffer);
John Stiles9cfaa4f2021-01-06 17:52:00 -05001203 for (int i = 0; i < type.columns(); i++) {
John Stilescd806892021-01-06 13:33:31 -05001204 this->writeWord(key.fValueId[i], fConstantBuffer);
1205 }
1206 iter->second = result;
1207 }
1208 return iter->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07001209}
1210
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001211SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001212 SkASSERT(c.arguments().size() == 1);
John Stilesd9d52712021-01-13 17:15:02 -05001213 SkASSERT(c.type().isFloat());
1214 const Expression& ctorExpr = *c.arguments()[0];
1215 SpvId expressionId = this->writeExpression(ctorExpr, out);
1216 return this->castScalarToFloat(expressionId, ctorExpr.type(), c.type(), out);
1217}
1218
1219SpvId SPIRVCodeGenerator::castScalarToFloat(SpvId inputId, const Type& inputType,
1220 const Type& outputType, OutputStream& out) {
1221 // Casting a float to float is a no-op.
1222 if (inputType.isFloat()) {
1223 return inputId;
1224 }
1225
1226 // Given the input type, generate the appropriate instruction to cast to float.
ethannicholasb3058bd2016-07-01 08:22:01 -07001227 SpvId result = this->nextId();
John Stilesd9d52712021-01-13 17:15:02 -05001228 if (inputType.isBoolean()) {
John Stilesba4b0e92021-01-05 13:55:39 -05001229 // Use OpSelect to convert the boolean argument to a literal 1.0 or 0.0.
1230 FloatLiteral one(fContext, /*offset=*/-1, /*value=*/1);
1231 SpvId oneID = this->writeFloatLiteral(one);
1232 FloatLiteral zero(fContext, /*offset=*/-1, /*value=*/0);
1233 SpvId zeroID = this->writeFloatLiteral(zero);
John Stilesd9d52712021-01-13 17:15:02 -05001234 this->writeInstruction(SpvOpSelect, this->getType(outputType), result,
1235 inputId, oneID, zeroID, out);
1236 } else if (inputType.isSigned()) {
1237 this->writeInstruction(SpvOpConvertSToF, this->getType(outputType), result, inputId, out);
1238 } else if (inputType.isUnsigned()) {
1239 this->writeInstruction(SpvOpConvertUToF, this->getType(outputType), result, inputId, out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001240 } else {
John Stilesd9d52712021-01-13 17:15:02 -05001241 SkDEBUGFAILF("unsupported type for float typecast: %s", inputType.description().c_str());
1242 return (SpvId)-1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001243 }
1244 return result;
1245}
1246
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001247SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001248 SkASSERT(c.arguments().size() == 1);
John Stilesd9d52712021-01-13 17:15:02 -05001249 SkASSERT(c.type().isSigned());
1250 const Expression& ctorExpr = *c.arguments()[0];
1251 SpvId expressionId = this->writeExpression(ctorExpr, out);
1252 return this->castScalarToSignedInt(expressionId, ctorExpr.type(), c.type(), out);
1253}
1254
1255SpvId SPIRVCodeGenerator::castScalarToSignedInt(SpvId inputId, const Type& inputType,
1256 const Type& outputType, OutputStream& out) {
1257 // Casting a signed int to signed int is a no-op.
1258 if (inputType.isSigned()) {
1259 return inputId;
1260 }
1261
1262 // Given the input type, generate the appropriate instruction to cast to signed int.
ethannicholasb3058bd2016-07-01 08:22:01 -07001263 SpvId result = this->nextId();
John Stilesd9d52712021-01-13 17:15:02 -05001264 if (inputType.isBoolean()) {
John Stilesba4b0e92021-01-05 13:55:39 -05001265 // Use OpSelect to convert the boolean argument to a literal 1 or 0.
John Stiles54e7c052021-01-11 14:22:36 -05001266 IntLiteral one(/*offset=*/-1, /*value=*/1, fContext.fTypes.fInt.get());
John Stilesba4b0e92021-01-05 13:55:39 -05001267 SpvId oneID = this->writeIntLiteral(one);
John Stiles54e7c052021-01-11 14:22:36 -05001268 IntLiteral zero(/*offset=*/-1, /*value=*/0, fContext.fTypes.fInt.get());
John Stilesba4b0e92021-01-05 13:55:39 -05001269 SpvId zeroID = this->writeIntLiteral(zero);
John Stilesd9d52712021-01-13 17:15:02 -05001270 this->writeInstruction(SpvOpSelect, this->getType(outputType), result,
1271 inputId, oneID, zeroID, out);
1272 } else if (inputType.isFloat()) {
1273 this->writeInstruction(SpvOpConvertFToS, this->getType(outputType), result, inputId, out);
1274 } else if (inputType.isUnsigned()) {
1275 this->writeInstruction(SpvOpBitcast, this->getType(outputType), result, inputId, out);
1276 } else {
1277 SkDEBUGFAILF("unsupported type for signed int typecast: %s",
1278 inputType.description().c_str());
1279 return (SpvId)-1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001280 }
1281 return result;
1282}
1283
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001284SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001285 SkASSERT(c.arguments().size() == 1);
John Stilesd9d52712021-01-13 17:15:02 -05001286 SkASSERT(c.type().isUnsigned());
1287 const Expression& ctorExpr = *c.arguments()[0];
1288 SpvId expressionId = this->writeExpression(ctorExpr, out);
1289 return this->castScalarToUnsignedInt(expressionId, ctorExpr.type(), c.type(), out);
1290}
1291
1292SpvId SPIRVCodeGenerator::castScalarToUnsignedInt(SpvId inputId, const Type& inputType,
1293 const Type& outputType, OutputStream& out) {
1294 // Casting an unsigned int to unsigned int is a no-op.
1295 if (inputType.isUnsigned()) {
1296 return inputId;
1297 }
1298
John Stiles48c28842021-01-14 11:05:03 -05001299 // Given the input type, generate the appropriate instruction to cast to unsigned int.
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001300 SpvId result = this->nextId();
John Stilesd9d52712021-01-13 17:15:02 -05001301 if (inputType.isBoolean()) {
John Stilesba4b0e92021-01-05 13:55:39 -05001302 // Use OpSelect to convert the boolean argument to a literal 1u or 0u.
John Stiles54e7c052021-01-11 14:22:36 -05001303 IntLiteral one(/*offset=*/-1, /*value=*/1, fContext.fTypes.fUInt.get());
John Stilesba4b0e92021-01-05 13:55:39 -05001304 SpvId oneID = this->writeIntLiteral(one);
John Stiles54e7c052021-01-11 14:22:36 -05001305 IntLiteral zero(/*offset=*/-1, /*value=*/0, fContext.fTypes.fUInt.get());
John Stilesba4b0e92021-01-05 13:55:39 -05001306 SpvId zeroID = this->writeIntLiteral(zero);
John Stilesd9d52712021-01-13 17:15:02 -05001307 this->writeInstruction(SpvOpSelect, this->getType(outputType), result,
1308 inputId, oneID, zeroID, out);
1309 } else if (inputType.isFloat()) {
1310 this->writeInstruction(SpvOpConvertFToU, this->getType(outputType), result, inputId, out);
1311 } else if (inputType.isSigned()) {
1312 this->writeInstruction(SpvOpBitcast, this->getType(outputType), result, inputId, out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001313 } else {
John Stilesd9d52712021-01-13 17:15:02 -05001314 SkDEBUGFAILF("unsupported type for unsigned int typecast: %s",
1315 inputType.description().c_str());
1316 return (SpvId)-1;
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001317 }
1318 return result;
1319}
1320
John Stilesa60fb172021-01-14 11:06:20 -05001321SpvId SPIRVCodeGenerator::writeBooleanConstructor(const Constructor& c, OutputStream& out) {
1322 SkASSERT(c.arguments().size() == 1);
1323 SkASSERT(c.type().isBoolean());
1324 const Expression& ctorExpr = *c.arguments()[0];
1325 SpvId expressionId = this->writeExpression(ctorExpr, out);
1326 return this->castScalarToBoolean(expressionId, ctorExpr.type(), c.type(), out);
1327}
1328
John Stiles48c28842021-01-14 11:05:03 -05001329SpvId SPIRVCodeGenerator::castScalarToBoolean(SpvId inputId, const Type& inputType,
1330 const Type& outputType, OutputStream& out) {
1331 // Casting a bool to bool is a no-op.
1332 if (inputType.isBoolean()) {
1333 return inputId;
1334 }
1335
1336 // Given the input type, generate the appropriate instruction to cast to bool.
1337 SpvId result = this->nextId();
1338 if (inputType.isSigned()) {
1339 // Synthesize a boolean result by comparing the input against a signed zero literal.
1340 IntLiteral zero(/*offset=*/-1, /*value=*/0, fContext.fTypes.fInt.get());
1341 SpvId zeroID = this->writeIntLiteral(zero);
1342 this->writeInstruction(SpvOpINotEqual, this->getType(outputType), result,
1343 inputId, zeroID, out);
1344 } else if (inputType.isUnsigned()) {
1345 // Synthesize a boolean result by comparing the input against an unsigned zero literal.
1346 IntLiteral zero(/*offset=*/-1, /*value=*/0, fContext.fTypes.fUInt.get());
1347 SpvId zeroID = this->writeIntLiteral(zero);
1348 this->writeInstruction(SpvOpINotEqual, this->getType(outputType), result,
1349 inputId, zeroID, out);
1350 } else if (inputType.isFloat()) {
1351 // Synthesize a boolean result by comparing the input against a floating-point zero literal.
1352 FloatLiteral zero(/*offset=*/-1, /*value=*/0, fContext.fTypes.fFloat.get());
1353 SpvId zeroID = this->writeFloatLiteral(zero);
1354 this->writeInstruction(SpvOpFUnordNotEqual, this->getType(outputType), result,
1355 inputId, zeroID, out);
1356 } else {
1357 SkDEBUGFAILF("unsupported type for boolean typecast: %s", inputType.description().c_str());
1358 return (SpvId)-1;
1359 }
1360 return result;
1361}
1362
Ethan Nicholas84645e32017-02-09 13:57:14 -05001363void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001364 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001365 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001366 SpvId zeroId = this->writeFloatLiteral(zero);
1367 std::vector<SpvId> columnIds;
1368 for (int column = 0; column < type.columns(); column++) {
1369 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1370 out);
1371 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1372 out);
1373 SpvId columnId = this->nextId();
1374 this->writeWord(columnId, out);
1375 columnIds.push_back(columnId);
1376 for (int row = 0; row < type.columns(); row++) {
1377 this->writeWord(row == column ? diagonal : zeroId, out);
1378 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001379 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001380 }
1381 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1382 out);
1383 this->writeWord(this->getType(type), out);
1384 this->writeWord(id, out);
John Stilesf621e232020-08-25 13:33:02 -04001385 for (SpvId columnId : columnIds) {
1386 this->writeWord(columnId, out);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001387 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001388 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001389}
1390
1391void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001392 const Type& dstType, OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05001393 SkASSERT(srcType.isMatrix());
1394 SkASSERT(dstType.isMatrix());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001395 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001396 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1397 srcType.rows(),
1398 1));
1399 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1400 dstType.rows(),
1401 1));
1402 SpvId zeroId;
John Stiles54e7c052021-01-11 14:22:36 -05001403 if (dstType.componentType() == *fContext.fTypes.fFloat) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001404 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001405 zeroId = this->writeFloatLiteral(zero);
John Stiles54e7c052021-01-11 14:22:36 -05001406 } else if (dstType.componentType() == *fContext.fTypes.fInt) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001407 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001408 zeroId = this->writeIntLiteral(zero);
1409 } else {
John Stilesf57207b2021-02-02 17:50:34 -05001410 SK_ABORT("unsupported matrix component type");
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001411 }
1412 SpvId zeroColumn = 0;
1413 SpvId columns[4];
1414 for (int i = 0; i < dstType.columns(); i++) {
1415 if (i < srcType.columns()) {
1416 // we're still inside the src matrix, copy the column
1417 SpvId srcColumn = this->nextId();
1418 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001419 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001420 SpvId dstColumn;
1421 if (srcType.rows() == dstType.rows()) {
1422 // columns are equal size, don't need to do anything
1423 dstColumn = srcColumn;
1424 }
1425 else if (dstType.rows() > srcType.rows()) {
1426 // dst column is bigger, need to zero-pad it
1427 dstColumn = this->nextId();
1428 int delta = dstType.rows() - srcType.rows();
1429 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1430 this->writeWord(dstColumnType, out);
1431 this->writeWord(dstColumn, out);
1432 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001433 for (int j = 0; j < delta; ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001434 this->writeWord(zeroId, out);
1435 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001436 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001437 }
1438 else {
1439 // dst column is smaller, need to swizzle the src column
1440 dstColumn = this->nextId();
1441 int count = dstType.rows();
1442 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1443 this->writeWord(dstColumnType, out);
1444 this->writeWord(dstColumn, out);
1445 this->writeWord(srcColumn, out);
1446 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001447 for (int j = 0; j < count; j++) {
1448 this->writeWord(j, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001449 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001450 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001451 }
1452 columns[i] = dstColumn;
1453 } else {
1454 // we're past the end of the src matrix, need a vector of zeroes
1455 if (!zeroColumn) {
1456 zeroColumn = this->nextId();
1457 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1458 this->writeWord(dstColumnType, out);
1459 this->writeWord(zeroColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001460 for (int j = 0; j < dstType.rows(); ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001461 this->writeWord(zeroId, out);
1462 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001463 this->writePrecisionModifier(dstType, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001464 }
1465 columns[i] = zeroColumn;
1466 }
1467 }
1468 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1469 this->writeWord(this->getType(dstType), out);
1470 this->writeWord(id, out);
1471 for (int i = 0; i < dstType.columns(); i++) {
1472 this->writeWord(columns[i], out);
1473 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001474 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001475}
1476
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001477void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1478 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001479 std::vector<SpvId>* columnIds,
1480 int* currentCount, int rows, SpvId entry,
1481 OutputStream& out) {
1482 SkASSERT(*currentCount < rows);
1483 ++(*currentCount);
1484 currentColumn->push_back(entry);
1485 if (*currentCount == rows) {
1486 *currentCount = 0;
1487 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1488 this->writeWord(columnType, out);
1489 SpvId columnId = this->nextId();
1490 this->writeWord(columnId, out);
1491 columnIds->push_back(columnId);
1492 for (SpvId id : *currentColumn) {
1493 this->writeWord(id, out);
1494 }
1495 currentColumn->clear();
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001496 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001497 }
1498}
1499
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001500SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001501 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001502 SkASSERT(type.isMatrix());
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001503 SkASSERT(c.arguments().size() > 0);
1504 const Type& arg0Type = c.arguments()[0]->type();
ethannicholasb3058bd2016-07-01 08:22:01 -07001505 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1506 // an instruction
1507 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001508 for (size_t i = 0; i < c.arguments().size(); i++) {
1509 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001510 }
1511 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001512 int rows = type.rows();
1513 int columns = type.columns();
John Stiles9aeed132020-11-24 17:36:06 -05001514 if (arguments.size() == 1 && arg0Type.isScalar()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001515 this->writeUniformScaleMatrix(result, arguments[0], type, out);
John Stiles9aeed132020-11-24 17:36:06 -05001516 } else if (arguments.size() == 1 && arg0Type.isMatrix()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001517 this->writeMatrixCopy(result, arguments[0], arg0Type, type, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001518 } else if (arguments.size() == 1 &&
John Stiles9aeed132020-11-24 17:36:06 -05001519 arg0Type.isVector()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001520 SkASSERT(type.rows() == 2 && type.columns() == 2);
1521 SkASSERT(arg0Type.columns() == 4);
1522 SpvId componentType = this->getType(type.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001523 SpvId v[4];
1524 for (int i = 0; i < 4; ++i) {
1525 v[i] = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001526 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i,
1527 out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001528 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001529 SpvId columnType = this->getType(type.componentType().toCompound(fContext, 2, 1));
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001530 SpvId column1 = this->nextId();
1531 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1532 SpvId column2 = this->nextId();
1533 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001534 this->writeInstruction(SpvOpCompositeConstruct, this->getType(type), result, column1,
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001535 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001536 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001537 SpvId columnType = this->getType(type.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001538 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001539 // ids of vectors and scalars we have written to the current column so far
1540 std::vector<SpvId> currentColumn;
1541 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001542 int currentCount = 0;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001543 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001544 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001545 const Type& argType = c.arguments()[i]->type();
John Stiles9aeed132020-11-24 17:36:06 -05001546 if (currentCount == 0 && argType.isVector() &&
Ethan Nicholas30d30222020-09-11 12:27:26 -04001547 argType.columns() == type.rows()) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001548 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001549 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001550 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001551 if (argType.columns() == 1) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001552 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1553 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001554 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001555 SpvId componentType = this->getType(argType.componentType());
1556 for (int j = 0; j < argType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001557 SpvId swizzle = this->nextId();
1558 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1559 arguments[i], j, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001560 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1561 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001562 }
1563 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001564 }
1565 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001566 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001567 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001568 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001569 this->writeWord(result, out);
1570 for (SpvId id : columnIds) {
1571 this->writeWord(id, out);
1572 }
1573 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001574 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001575 return result;
1576}
1577
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001578SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001579 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001580 SkASSERT(type.isVector());
Brian Osman0247e9e2020-12-23 15:07:11 -05001581 // Constructing a vector from another vector (even if it's constant) requires our general
1582 // case code, to deal with (possible) per-element type conversion.
1583 bool vectorToVector = c.arguments().size() == 1 && c.arguments()[0]->type().isVector();
1584 if (c.isCompileTimeConstant() && !vectorToVector) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001585 return this->writeConstantVector(c);
1586 }
1587 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1588 // an instruction
1589 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001590 for (size_t i = 0; i < c.arguments().size(); i++) {
1591 const Type& argType = c.arguments()[i]->type();
John Stiles9aeed132020-11-24 17:36:06 -05001592 if (argType.isVector()) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001593 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1594 // extract the components and convert them in that case manually. On top of that,
John Stilesd5e59b62021-01-13 13:09:26 -05001595 // as of this writing there's a bug in the Intel Vulkan driver where
1596 // OpCompositeConstruct doesn't handle vector arguments at all, so we always extract
1597 // vector components and pass them into OpCompositeConstruct individually.
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001598 SpvId vec = this->writeExpression(*c.arguments()[i], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001599 const Type& src = argType.componentType();
1600 const Type& dst = type.componentType();
John Stiles48c28842021-01-14 11:05:03 -05001601 if (c.arguments().size() == 1 && src.numberKind() == dst.numberKind()) {
1602 return vec;
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001603 }
John Stiles48c28842021-01-14 11:05:03 -05001604
Ethan Nicholas30d30222020-09-11 12:27:26 -04001605 for (int j = 0; j < argType.columns(); j++) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001606 SpvId swizzle = this->nextId();
1607 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1608 out);
John Stiles48c28842021-01-14 11:05:03 -05001609 if (dst.isFloat()) {
1610 arguments.push_back(this->castScalarToFloat(swizzle, src, dst, out));
1611 } else if (dst.isSigned()) {
1612 arguments.push_back(this->castScalarToSignedInt(swizzle, src, dst, out));
1613 } else if (dst.isUnsigned()) {
1614 arguments.push_back(this->castScalarToUnsignedInt(swizzle, src, dst, out));
1615 } else if (dst.isBoolean()) {
1616 arguments.push_back(this->castScalarToBoolean(swizzle, src, dst, out));
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001617 } else {
1618 arguments.push_back(swizzle);
John Stiles48c28842021-01-14 11:05:03 -05001619 fErrors.error(c.arguments()[i]->fOffset, "unsupported cast in SPIR-V: vector " +
1620 src.description() + " to " +
1621 dst.description());
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001622 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001623 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001624 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001625 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001626 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001627 }
1628 SpvId result = this->nextId();
John Stiles9aeed132020-11-24 17:36:06 -05001629 if (arguments.size() == 1 && c.arguments()[0]->type().isScalar()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001630 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(), out);
1631 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001632 this->writeWord(result, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001633 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001634 this->writeWord(arguments[0], out);
1635 }
1636 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001637 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001638 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001639 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001640 this->writeWord(result, out);
1641 for (SpvId id : arguments) {
1642 this->writeWord(id, out);
1643 }
1644 }
1645 return result;
1646}
1647
Ethan Nicholasbd553222017-07-18 15:54:59 -04001648SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001649 const Type& type = c.type();
John Stilesc0c51062020-12-03 17:16:29 -05001650 SkASSERT(type.isArray());
Ethan Nicholasbd553222017-07-18 15:54:59 -04001651 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1652 // an instruction
1653 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001654 for (size_t i = 0; i < c.arguments().size(); i++) {
1655 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholasbd553222017-07-18 15:54:59 -04001656 }
1657 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001658 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.arguments().size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001659 this->writeWord(this->getType(type), out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001660 this->writeWord(result, out);
1661 for (SpvId id : arguments) {
1662 this->writeWord(id, out);
1663 }
1664 return result;
1665}
1666
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001667SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001668 const Type& type = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001669 if (c.arguments().size() == 1 &&
1670 this->getActualType(type) == this->getActualType(c.arguments()[0]->type())) {
1671 return this->writeExpression(*c.arguments()[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001672 }
John Stilese3183552021-01-13 19:34:17 -05001673 if (type.isFloat()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001674 return this->writeFloatConstructor(c, out);
John Stilese3183552021-01-13 19:34:17 -05001675 } else if (type.isSigned()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001676 return this->writeIntConstructor(c, out);
John Stilese3183552021-01-13 19:34:17 -05001677 } else if (type.isUnsigned()) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001678 return this->writeUIntConstructor(c, out);
John Stilesa60fb172021-01-14 11:06:20 -05001679 } else if (type.isBoolean()) {
1680 return this->writeBooleanConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001681 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001682 switch (type.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001683 case Type::TypeKind::kVector:
ethannicholasb3058bd2016-07-01 08:22:01 -07001684 return this->writeVectorConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001685 case Type::TypeKind::kMatrix:
ethannicholasb3058bd2016-07-01 08:22:01 -07001686 return this->writeMatrixConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001687 case Type::TypeKind::kArray:
Ethan Nicholasbd553222017-07-18 15:54:59 -04001688 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001689 default:
John Stilese3183552021-01-13 19:34:17 -05001690 fErrors.error(c.fOffset, "unsupported constructor: " + c.description());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001691 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001692 }
1693}
1694
John Stiles9485b552021-01-27 11:47:00 -05001695static SpvStorageClass_ get_storage_class(const Variable& var,
1696 SpvStorageClass_ fallbackStorageClass) {
1697 const Modifiers& modifiers = var.modifiers();
ethannicholasb3058bd2016-07-01 08:22:01 -07001698 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001699 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001700 return SpvStorageClassInput;
John Stiles9485b552021-01-27 11:47:00 -05001701 }
1702 if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001703 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001704 return SpvStorageClassOutput;
John Stiles9485b552021-01-27 11:47:00 -05001705 }
1706 if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001707 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001708 return SpvStorageClassPushConstant;
1709 }
John Stiles9485b552021-01-27 11:47:00 -05001710 if (var.type().typeKind() == Type::TypeKind::kSampler ||
1711 var.type().typeKind() == Type::TypeKind::kSeparateSampler ||
1712 var.type().typeKind() == Type::TypeKind::kTexture) {
1713 return SpvStorageClassUniformConstant;
1714 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001715 return SpvStorageClassUniform;
ethannicholasb3058bd2016-07-01 08:22:01 -07001716 }
John Stiles9485b552021-01-27 11:47:00 -05001717 return fallbackStorageClass;
ethannicholasb3058bd2016-07-01 08:22:01 -07001718}
1719
John Stiles9485b552021-01-27 11:47:00 -05001720static SpvStorageClass_ get_storage_class(const Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001721 switch (expr.kind()) {
1722 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -04001723 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001724 if (var.storage() != Variable::Storage::kGlobal) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001725 return SpvStorageClassFunction;
1726 }
John Stiles9485b552021-01-27 11:47:00 -05001727 return get_storage_class(var, SpvStorageClassPrivate);
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001728 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001729 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001730 return get_storage_class(*expr.as<FieldAccess>().base());
Ethan Nicholase6592142020-09-08 10:22:09 -04001731 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001732 return get_storage_class(*expr.as<IndexExpression>().base());
ethannicholasb3058bd2016-07-01 08:22:01 -07001733 default:
1734 return SpvStorageClassFunction;
1735 }
1736}
1737
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001738std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001739 std::vector<SpvId> chain;
Ethan Nicholase6592142020-09-08 10:22:09 -04001740 switch (expr.kind()) {
1741 case Expression::Kind::kIndex: {
John Stiles0693fb82021-01-22 18:27:52 -05001742 const IndexExpression& indexExpr = expr.as<IndexExpression>();
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001743 chain = this->getAccessChain(*indexExpr.base(), out);
1744 chain.push_back(this->writeExpression(*indexExpr.index(), out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001745 break;
1746 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001747 case Expression::Kind::kFieldAccess: {
John Stiles0693fb82021-01-22 18:27:52 -05001748 const FieldAccess& fieldExpr = expr.as<FieldAccess>();
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001749 chain = this->getAccessChain(*fieldExpr.base(), out);
John Stilese40d1662021-01-29 10:08:50 -05001750 IntLiteral index(fContext, /*offset=*/-1, fieldExpr.fieldIndex());
ethannicholasb3058bd2016-07-01 08:22:01 -07001751 chain.push_back(this->writeIntLiteral(index));
1752 break;
1753 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001754 default: {
1755 SpvId id = this->getLValue(expr, out)->getPointer();
John Stiles3f14d282021-02-05 09:31:04 -05001756 SkASSERT(id != (SpvId) -1);
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001757 chain.push_back(id);
1758 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001759 }
1760 return chain;
1761}
1762
1763class PointerLValue : public SPIRVCodeGenerator::LValue {
1764public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001765 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1766 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001767 : fGen(gen)
1768 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001769 , fType(type)
1770 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001771
John Stiles1cf2c8d2020-08-13 22:58:04 -04001772 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001773 return fPointer;
1774 }
1775
John Stiles1cf2c8d2020-08-13 22:58:04 -04001776 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001777 SpvId result = fGen.nextId();
1778 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001779 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001780 return result;
1781 }
1782
John Stiles1cf2c8d2020-08-13 22:58:04 -04001783 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001784 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1785 }
1786
1787private:
1788 SPIRVCodeGenerator& fGen;
1789 const SpvId fPointer;
1790 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001791 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001792};
1793
1794class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1795public:
John Stiles750109b2020-10-30 13:45:46 -04001796 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const ComponentArray& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001797 const Type& baseType, const Type& swizzleType,
1798 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001799 : fGen(gen)
1800 , fVecPointer(vecPointer)
1801 , fComponents(components)
John Stiles3f14d282021-02-05 09:31:04 -05001802 , fBaseType(&baseType)
1803 , fSwizzleType(&swizzleType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001804 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001805
John Stiles3f14d282021-02-05 09:31:04 -05001806 bool applySwizzle(const ComponentArray& components, const Type& newType) override {
1807 ComponentArray updatedSwizzle;
1808 for (int8_t component : components) {
1809 if (component < 0 || component >= fComponents.count()) {
1810 SkDEBUGFAILF("swizzle accessed nonexistent component %d", (int)component);
1811 return false;
1812 }
1813 updatedSwizzle.push_back(fComponents[component]);
1814 }
1815 fComponents = updatedSwizzle;
1816 fSwizzleType = &newType;
1817 return true;
ethannicholasb3058bd2016-07-01 08:22:01 -07001818 }
1819
John Stiles1cf2c8d2020-08-13 22:58:04 -04001820 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001821 SpvId base = fGen.nextId();
John Stiles3f14d282021-02-05 09:31:04 -05001822 fGen.writeInstruction(SpvOpLoad, fGen.getType(*fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001823 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001824 SpvId result = fGen.nextId();
1825 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
John Stiles3f14d282021-02-05 09:31:04 -05001826 fGen.writeWord(fGen.getType(*fSwizzleType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001827 fGen.writeWord(result, out);
1828 fGen.writeWord(base, out);
1829 fGen.writeWord(base, out);
1830 for (int component : fComponents) {
1831 fGen.writeWord(component, out);
1832 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001833 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001834 return result;
1835 }
1836
John Stiles1cf2c8d2020-08-13 22:58:04 -04001837 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001838 // use OpVectorShuffle to mix and match the vector components. We effectively create
1839 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001840 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001841 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001842 // float3L = ...;
1843 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001844 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001845 // we end up with the virtual vector (L.x, L.y, L.z, R.x, R.y, R.z). Then we want
ethannicholasb3058bd2016-07-01 08:22:01 -07001846 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1847 // (3, 1, 4).
1848 SpvId base = fGen.nextId();
John Stiles3f14d282021-02-05 09:31:04 -05001849 fGen.writeInstruction(SpvOpLoad, fGen.getType(*fBaseType), base, fVecPointer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001850 SpvId shuffle = fGen.nextId();
John Stiles3f14d282021-02-05 09:31:04 -05001851 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType->columns(), out);
1852 fGen.writeWord(fGen.getType(*fBaseType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001853 fGen.writeWord(shuffle, out);
1854 fGen.writeWord(base, out);
1855 fGen.writeWord(value, out);
John Stiles3f14d282021-02-05 09:31:04 -05001856 for (int i = 0; i < fBaseType->columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001857 // current offset into the virtual vector, defaults to pulling the unmodified
1858 // value from the left side
1859 int offset = i;
1860 // check to see if we are writing this component
1861 for (size_t j = 0; j < fComponents.size(); j++) {
1862 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001863 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001864 // the correct component of the right side instead of preserving the
1865 // value from the left
John Stiles3f14d282021-02-05 09:31:04 -05001866 offset = (int) (j + fBaseType->columns());
ethannicholasb3058bd2016-07-01 08:22:01 -07001867 break;
1868 }
1869 }
1870 fGen.writeWord(offset, out);
1871 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001872 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001873 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1874 }
1875
1876private:
1877 SPIRVCodeGenerator& fGen;
1878 const SpvId fVecPointer;
John Stiles3f14d282021-02-05 09:31:04 -05001879 ComponentArray fComponents;
1880 const Type* fBaseType;
1881 const Type* fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001882 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001883};
1884
John Stilese40d1662021-01-29 10:08:50 -05001885int SPIRVCodeGenerator::findUniformFieldIndex(const Variable& var) const {
1886 auto iter = fTopLevelUniformMap.find(&var);
1887 return (iter != fTopLevelUniformMap.end()) ? iter->second : -1;
1888}
1889
Greg Daniel64773e62016-11-22 09:44:03 -05001890std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001891 OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001892 const Type& type = expr.type();
1893 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
Ethan Nicholase6592142020-09-08 10:22:09 -04001894 switch (expr.kind()) {
1895 case Expression::Kind::kVariableReference: {
John Stiles0de76f72021-01-29 09:19:39 -05001896 const Variable& var = *expr.as<VariableReference>().variable();
John Stilese40d1662021-01-29 10:08:50 -05001897 int uniformIdx = this->findUniformFieldIndex(var);
1898 if (uniformIdx >= 0) {
1899 IntLiteral uniformIdxLiteral{fContext, /*offset=*/-1, uniformIdx};
1900 SpvId memberId = this->nextId();
1901 SpvId typeId = this->getPointerType(type, SpvStorageClassUniform);
1902 SpvId uniformIdxId = this->writeIntLiteral(uniformIdxLiteral);
1903 this->writeInstruction(SpvOpAccessChain, typeId, memberId, fUniformBufferId,
1904 uniformIdxId, out);
1905 return std::make_unique<PointerLValue>(*this, memberId, this->getType(type),
1906 precision);
1907 }
1908 SpvId typeId;
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001909 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
John Stilesad2d4942020-12-11 16:55:58 -05001910 typeId = this->getType(*Type::MakeArrayType("sk_in", var.type().componentType(),
1911 fSkInCount));
Ethan Nicholas5226b772018-05-03 16:20:41 -04001912 } else {
Brian Osman2a4c0fb2021-01-22 13:41:40 -05001913 typeId = this->getType(type, this->memoryLayoutForVariable(var));
Ethan Nicholas5226b772018-05-03 16:20:41 -04001914 }
ethannicholasd598f792016-07-25 10:08:54 -07001915 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001916 SkASSERT(entry != fVariableMap.end());
John Stiles5570c512020-11-19 17:58:07 -05001917 return std::make_unique<PointerLValue>(*this, entry->second, typeId, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001918 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001919 case Expression::Kind::kIndex: // fall through
1920 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001921 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1922 SpvId member = this->nextId();
1923 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001924 this->writeWord(this->getPointerType(type, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001925 this->writeWord(member, out);
1926 for (SpvId idx : chain) {
1927 this->writeWord(idx, out);
1928 }
John Stiles5570c512020-11-19 17:58:07 -05001929 return std::make_unique<PointerLValue>(*this, member, this->getType(type), precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001930 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001931 case Expression::Kind::kSwizzle: {
John Stiles0693fb82021-01-22 18:27:52 -05001932 const Swizzle& swizzle = expr.as<Swizzle>();
John Stiles3f14d282021-02-05 09:31:04 -05001933 std::unique_ptr<LValue> lvalue = this->getLValue(*swizzle.base(), out);
1934 if (lvalue->applySwizzle(swizzle.components(), type)) {
1935 return lvalue;
1936 }
1937 SpvId base = lvalue->getPointer();
1938 if (base == (SpvId) -1) {
John Stiles5570c512020-11-19 17:58:07 -05001939 fErrors.error(swizzle.fOffset, "unable to retrieve lvalue from swizzle");
1940 }
John Stiles3f14d282021-02-05 09:31:04 -05001941 if (swizzle.components().size() == 1) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001942 SpvId member = this->nextId();
John Stilesb5db4822021-01-21 13:04:40 -05001943 SpvId typeId = this->getPointerType(type, get_storage_class(*swizzle.base()));
1944 IntLiteral index(fContext, /*offset=*/-1, swizzle.components()[0]);
1945 SpvId indexId = this->writeIntLiteral(index);
1946 this->writeInstruction(SpvOpAccessChain, typeId, member, base, indexId, out);
John Stiles5570c512020-11-19 17:58:07 -05001947 return std::make_unique<PointerLValue>(*this, member, this->getType(type),
1948 precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001949 } else {
John Stiles5570c512020-11-19 17:58:07 -05001950 return std::make_unique<SwizzleLValue>(*this, base, swizzle.components(),
1951 swizzle.base()->type(), type, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001952 }
1953 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001954 default: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001955 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001956 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001957 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1958 // caught by IRGenerator
1959 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001960 SpvId pointerType = this->getPointerType(type, SpvStorageClassFunction);
1961 this->writeInstruction(SpvOpVariable, pointerType, result, SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001962 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001963 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
John Stiles5570c512020-11-19 17:58:07 -05001964 return std::make_unique<PointerLValue>(*this, result, this->getType(type), precision);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001965 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001966 }
1967}
1968
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001969SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
John Stiles1e1fe122021-01-29 12:18:46 -05001970 SpvId result = this->getLValue(ref, out)->load(out);
John Stilese40d1662021-01-29 10:08:50 -05001971
John Stiles1e1fe122021-01-29 12:18:46 -05001972 // Handle the "flipY" setting when reading sk_FragCoord.
1973 const Variable* variable = ref.variable();
John Stilese40d1662021-01-29 10:08:50 -05001974 if (variable->modifiers().fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
John Stiles270cec22021-02-17 12:59:36 -05001975 fProgram.fConfig->fSettings.fFlipY) {
Greg Daniela85e4bf2020-06-17 16:32:45 -04001976 // The x component never changes, so just grab it
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001977 SpvId xId = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05001978 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fTypes.fFloat), xId,
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001979 result, 0, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001980
1981 // Calculate the y component which may need to be flipped
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001982 SpvId rawYId = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05001983 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fTypes.fFloat),
1984 rawYId, result, 1, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001985 SpvId flippedYId = 0;
John Stiles270cec22021-02-17 12:59:36 -05001986 if (fProgram.fConfig->fSettings.fFlipY) {
Greg Daniela85e4bf2020-06-17 16:32:45 -04001987 // need to remap to a top-left coordinate system
1988 if (fRTHeightStructId == (SpvId)-1) {
1989 // height variable hasn't been written yet
Greg Daniela85e4bf2020-06-17 16:32:45 -04001990 SkASSERT(fRTHeightFieldIndex == (SpvId)-1);
1991 std::vector<Type::Field> fields;
John Stiles270cec22021-02-17 12:59:36 -05001992 if (fProgram.fConfig->fSettings.fRTHeightOffset < 0) {
John Stiles5570c512020-11-19 17:58:07 -05001993 fErrors.error(ref.fOffset, "RTHeightOffset is negative");
1994 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001995 fields.emplace_back(
John Stilese40d1662021-01-29 10:08:50 -05001996 Modifiers(Layout(/*flags=*/0, /*location=*/-1,
John Stiles270cec22021-02-17 12:59:36 -05001997 fProgram.fConfig->fSettings.fRTHeightOffset,
John Stilese40d1662021-01-29 10:08:50 -05001998 /*binding=*/-1, /*index=*/-1, /*set=*/-1, /*builtin=*/-1,
Brian Osman4717fbb2021-02-23 13:12:09 -05001999 /*inputAttachmentIndex=*/-1,
John Stilese40d1662021-01-29 10:08:50 -05002000 Layout::kUnspecified_Primitive, /*maxVertices=*/1,
2001 /*invocations=*/-1, /*marker=*/"", /*when=*/"",
Greg Daniela85e4bf2020-06-17 16:32:45 -04002002 Layout::kNo_Key, Layout::CType::kDefault),
John Stilese40d1662021-01-29 10:08:50 -05002003 /*flags=*/0),
John Stiles54e7c052021-01-11 14:22:36 -05002004 SKSL_RTHEIGHT_NAME, fContext.fTypes.fFloat.get());
Greg Daniela85e4bf2020-06-17 16:32:45 -04002005 StringFragment name("sksl_synthetic_uniforms");
John Stilesad2d4942020-12-11 16:55:58 -05002006 std::unique_ptr<Type> intfStruct = Type::MakeStructType(/*offset=*/-1, name,
2007 fields);
John Stiles270cec22021-02-17 12:59:36 -05002008 int binding = fProgram.fConfig->fSettings.fRTHeightBinding;
John Stiles5570c512020-11-19 17:58:07 -05002009 if (binding == -1) {
2010 fErrors.error(ref.fOffset, "layout(binding=...) is required in SPIR-V");
2011 }
John Stiles270cec22021-02-17 12:59:36 -05002012 int set = fProgram.fConfig->fSettings.fRTHeightSet;
John Stiles5570c512020-11-19 17:58:07 -05002013 if (set == -1) {
2014 fErrors.error(ref.fOffset, "layout(set=...) is required in SPIR-V");
2015 }
John Stiles270cec22021-02-17 12:59:36 -05002016 bool usePushConstants = fProgram.fConfig->fSettings.fUsePushConstants;
John Stilese40d1662021-01-29 10:08:50 -05002017 int flags = usePushConstants ? Layout::Flag::kPushConstant_Flag : 0;
2018 Modifiers modifiers(
2019 Layout(flags, /*location=*/-1, /*offset=*/-1, binding, /*index=*/-1,
2020 set, /*builtin=*/-1, /*inputAttachmentIndex=*/-1,
Brian Osman4717fbb2021-02-23 13:12:09 -05002021 Layout::kUnspecified_Primitive,
John Stilese40d1662021-01-29 10:08:50 -05002022 /*maxVertices=*/-1, /*invocations=*/-1, /*marker=*/"", /*when=*/"",
2023 Layout::kNo_Key, Layout::CType::kDefault),
2024 Modifiers::kUniform_Flag);
John Stiles3ae071e2020-08-05 15:29:29 -04002025 const Variable* intfVar = fSynthetics.takeOwnershipOfSymbol(
2026 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -05002027 fProgram.fModifiers->addToPool(modifiers),
John Stiles3ae071e2020-08-05 15:29:29 -04002028 name,
John Stilesad2d4942020-12-11 16:55:58 -05002029 intfStruct.get(),
Brian Osman3887a012020-09-30 13:22:27 -04002030 /*builtin=*/false,
Ethan Nicholas453f67f2020-10-09 10:43:45 -04002031 Variable::Storage::kGlobal));
John Stilesd39aec02020-12-03 10:42:26 -05002032 InterfaceBlock intf(/*offset=*/-1, intfVar, name,
2033 /*instanceName=*/"", /*arraySize=*/0,
John Stiles7c3515b2020-10-16 18:38:39 -04002034 std::make_shared<SymbolTable>(&fErrors, /*builtin=*/false));
Stephen White88574972020-06-23 19:09:29 -04002035
2036 fRTHeightStructId = this->writeInterfaceBlock(intf, false);
Greg Daniela85e4bf2020-06-17 16:32:45 -04002037 fRTHeightFieldIndex = 0;
Jim Van Verth46e9b0e2021-01-28 17:26:48 -05002038 fRTHeightStorageClass = usePushConstants ? SpvStorageClassPushConstant
2039 : SpvStorageClassUniform;
Greg Daniela85e4bf2020-06-17 16:32:45 -04002040 }
2041 SkASSERT(fRTHeightFieldIndex != (SpvId)-1);
2042
2043 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
2044 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
2045 SpvId heightPtr = this->nextId();
2046 this->writeOpCode(SpvOpAccessChain, 5, out);
John Stiles54e7c052021-01-11 14:22:36 -05002047 this->writeWord(this->getPointerType(*fContext.fTypes.fFloat, fRTHeightStorageClass),
Greg Daniela85e4bf2020-06-17 16:32:45 -04002048 out);
2049 this->writeWord(heightPtr, out);
2050 this->writeWord(fRTHeightStructId, out);
2051 this->writeWord(fieldIndexId, out);
2052 SpvId heightRead = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05002053 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fTypes.fFloat), heightRead,
Greg Daniela85e4bf2020-06-17 16:32:45 -04002054 heightPtr, out);
2055
2056 flippedYId = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05002057 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fTypes.fFloat), flippedYId,
Greg Daniela85e4bf2020-06-17 16:32:45 -04002058 heightRead, rawYId, out);
2059 }
2060
2061 // The z component will always be zero so we just get an id to the 0 literal
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002062 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002063 SpvId zeroId = writeFloatLiteral(zero);
Greg Daniela85e4bf2020-06-17 16:32:45 -04002064
Brian Osmane38bedd2020-12-21 11:51:54 -05002065 // Calculate the w component
Greg Daniela85e4bf2020-06-17 16:32:45 -04002066 SpvId rawWId = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05002067 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fTypes.fFloat),
2068 rawWId, result, 3, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04002069
2070 // Fill in the new fragcoord with the components from above
2071 SpvId adjusted = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002072 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
John Stiles54e7c052021-01-11 14:22:36 -05002073 this->writeWord(this->getType(*fContext.fTypes.fFloat4), out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04002074 this->writeWord(adjusted, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002075 this->writeWord(xId, out);
John Stiles270cec22021-02-17 12:59:36 -05002076 if (fProgram.fConfig->fSettings.fFlipY) {
Greg Daniela85e4bf2020-06-17 16:32:45 -04002077 this->writeWord(flippedYId, out);
2078 } else {
2079 this->writeWord(rawYId, out);
2080 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002081 this->writeWord(zeroId, out);
Brian Osmane38bedd2020-12-21 11:51:54 -05002082 this->writeWord(rawWId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04002083
2084 return adjusted;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002085 }
John Stiles1e1fe122021-01-29 12:18:46 -05002086
2087 // Handle the "flipY" setting when reading sk_Clockwise.
John Stilese40d1662021-01-29 10:08:50 -05002088 if (variable->modifiers().fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
John Stiles270cec22021-02-17 12:59:36 -05002089 !fProgram.fConfig->fSettings.fFlipY) {
Chris Daltonb91c4662018-08-01 10:46:22 -06002090 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
2091 // the default convention of "counter-clockwise face is front".
2092 SpvId inverse = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05002093 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fTypes.fBool), inverse,
Chris Daltonb91c4662018-08-01 10:46:22 -06002094 result, out);
2095 return inverse;
2096 }
John Stiles1e1fe122021-01-29 12:18:46 -05002097
ethannicholasb3058bd2016-07-01 08:22:01 -07002098 return result;
2099}
2100
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002101SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05002102 if (expr.base()->type().isVector()) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04002103 SpvId base = this->writeExpression(*expr.base(), out);
2104 SpvId index = this->writeExpression(*expr.index(), out);
Ethan Nicholasa9a06902019-01-07 14:42:40 -05002105 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002106 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.type()), result, base,
Ethan Nicholasa9a06902019-01-07 14:42:40 -05002107 index, out);
2108 return result;
2109 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002110 return getLValue(expr, out)->load(out);
2111}
2112
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002113SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002114 return getLValue(f, out)->load(out);
2115}
2116
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002117SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002118 SpvId base = this->writeExpression(*swizzle.base(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002119 SpvId result = this->nextId();
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002120 size_t count = swizzle.components().size();
ethannicholasb3058bd2016-07-01 08:22:01 -07002121 if (count == 1) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002122 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.type()), result, base,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002123 swizzle.components()[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002124 } else {
2125 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002126 this->writeWord(this->getType(swizzle.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002127 this->writeWord(result, out);
2128 this->writeWord(base, out);
Brian Osman25647672020-09-15 15:16:56 -04002129 this->writeWord(base, out);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002130 for (int component : swizzle.components()) {
Brian Osman25647672020-09-15 15:16:56 -04002131 this->writeWord(component, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002132 }
2133 }
2134 return result;
2135}
2136
Greg Daniel64773e62016-11-22 09:44:03 -05002137SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
2138 const Type& operandType, SpvId lhs,
2139 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002140 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002141 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002142 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002143 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002144 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002145 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002146 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002147 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
John Stiles123501f2020-12-09 10:08:13 -05002148 } else if (is_bool(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002149 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002150 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07002151 } else {
John Stiles123501f2020-12-09 10:08:13 -05002152 fErrors.error(operandType.fOffset,
2153 "unsupported operand for binary expression: " + operandType.description());
2154 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002155 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04002156 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002157 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
2158 fDecorationBuffer);
2159 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002160 return result;
2161}
2162
Ethan Nicholas48e24052018-03-14 13:51:39 -04002163SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
2164 OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05002165 if (operandType.isVector()) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002166 SpvId result = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05002167 this->writeInstruction(op, this->getType(*fContext.fTypes.fBool), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002168 return result;
2169 }
2170 return id;
2171}
2172
Ethan Nicholas68990be2017-07-13 09:36:52 -04002173SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
2174 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002175 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04002176 OutputStream& out) {
2177 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
John Stiles9aeed132020-11-24 17:36:06 -05002178 SkASSERT(operandType.isMatrix());
Ethan Nicholas0df21132018-07-10 09:37:51 -04002179 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2180 operandType.rows(),
2181 1));
John Stiles54e7c052021-01-11 14:22:36 -05002182 SpvId bvecType = this->getType(fContext.fTypes.fBool->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002183 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04002184 1));
John Stiles54e7c052021-01-11 14:22:36 -05002185 SpvId boolType = this->getType(*fContext.fTypes.fBool);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002186 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04002187 for (int i = 0; i < operandType.columns(); i++) {
2188 SpvId columnL = this->nextId();
2189 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2190 SpvId columnR = this->nextId();
2191 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002192 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002193 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
2194 SpvId merge = this->nextId();
2195 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002196 if (result != 0) {
2197 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002198 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002199 result = next;
2200 }
2201 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002202 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04002203 }
2204 }
2205 return result;
2206}
2207
Ethan Nicholas0df21132018-07-10 09:37:51 -04002208SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
2209 SpvId rhs, SpvOp_ floatOperator,
2210 SpvOp_ intOperator,
2211 OutputStream& out) {
2212 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
John Stiles9aeed132020-11-24 17:36:06 -05002213 SkASSERT(operandType.isMatrix());
Ethan Nicholas0df21132018-07-10 09:37:51 -04002214 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2215 operandType.rows(),
2216 1));
2217 SpvId columns[4];
2218 for (int i = 0; i < operandType.columns(); i++) {
2219 SpvId columnL = this->nextId();
2220 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2221 SpvId columnR = this->nextId();
2222 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2223 columns[i] = this->nextId();
2224 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2225 }
2226 SpvId result = this->nextId();
2227 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2228 this->writeWord(this->getType(operandType), out);
2229 this->writeWord(result, out);
2230 for (int i = 0; i < operandType.columns(); i++) {
2231 this->writeWord(columns[i], out);
2232 }
2233 return result;
2234}
2235
John Stiles9485b552021-01-27 11:47:00 -05002236static std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002237 if (type.isInteger()) {
2238 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002239 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002240 else if (type.isFloat()) {
2241 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002242 } else {
John Stilesf57207b2021-02-02 17:50:34 -05002243 SK_ABORT("math is unsupported on type '%s'", String(type.name()).c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002244 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002245}
2246
John Stiles45990502021-02-16 10:55:27 -05002247SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Operator op,
Ethan Nicholas49465b42019-04-17 12:22:21 -04002248 const Type& rightType, SpvId rhs,
2249 const Type& resultType, OutputStream& out) {
John Stilesd0614f22020-12-09 11:11:41 -05002250 // The comma operator ignores the type of the left-hand side entirely.
John Stiles45990502021-02-16 10:55:27 -05002251 if (op.kind() == Token::Kind::TK_COMMA) {
John Stilesd0614f22020-12-09 11:11:41 -05002252 return rhs;
2253 }
Ethan Nicholas48e24052018-03-14 13:51:39 -04002254 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002255 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002256 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2257 // handling in SPIR-V
Ethan Nicholas49465b42019-04-17 12:22:21 -04002258 if (this->getActualType(leftType) != this->getActualType(rightType)) {
John Stiles9aeed132020-11-24 17:36:06 -05002259 if (leftType.isVector() && rightType.isNumber()) {
John Stiles45990502021-02-16 10:55:27 -05002260 if (op.kind() == Token::Kind::TK_SLASH) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002261 SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
2262 SpvId inverse = this->nextId();
2263 this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
2264 rhs = inverse;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002265 op = Token::Kind::TK_STAR;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002266 }
John Stiles45990502021-02-16 10:55:27 -05002267 if (op.kind() == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002268 SpvId result = this->nextId();
2269 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2270 result, lhs, rhs, out);
2271 return result;
2272 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002273 // promote number to vector
2274 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002275 const Type& vecType = leftType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002276 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2277 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002278 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002279 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002280 this->writeWord(rhs, out);
2281 }
2282 rhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002283 operandType = &leftType;
John Stiles9aeed132020-11-24 17:36:06 -05002284 } else if (rightType.isVector() && leftType.isNumber()) {
John Stiles45990502021-02-16 10:55:27 -05002285 if (op.kind() == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002286 SpvId result = this->nextId();
2287 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2288 result, rhs, lhs, out);
2289 return result;
2290 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002291 // promote number to vector
2292 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002293 const Type& vecType = rightType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002294 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2295 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002296 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002297 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002298 this->writeWord(lhs, out);
2299 }
2300 lhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002301 operandType = &rightType;
John Stiles9aeed132020-11-24 17:36:06 -05002302 } else if (leftType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002303 SpvOp_ spvop;
John Stiles9aeed132020-11-24 17:36:06 -05002304 if (rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002305 spvop = SpvOpMatrixTimesMatrix;
John Stiles9aeed132020-11-24 17:36:06 -05002306 } else if (rightType.isVector()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002307 spvop = SpvOpMatrixTimesVector;
ethannicholasb3058bd2016-07-01 08:22:01 -07002308 } else {
John Stiles9aeed132020-11-24 17:36:06 -05002309 SkASSERT(rightType.isScalar());
Ethan Nicholas49465b42019-04-17 12:22:21 -04002310 spvop = SpvOpMatrixTimesScalar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002311 }
2312 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002313 this->writeInstruction(spvop, this->getType(resultType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002314 return result;
John Stiles9aeed132020-11-24 17:36:06 -05002315 } else if (rightType.isMatrix()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002316 SpvId result = this->nextId();
John Stiles9aeed132020-11-24 17:36:06 -05002317 if (leftType.isVector()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002318 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(resultType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002319 lhs, rhs, out);
2320 } else {
John Stiles9aeed132020-11-24 17:36:06 -05002321 SkASSERT(leftType.isScalar());
Ethan Nicholas49465b42019-04-17 12:22:21 -04002322 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(resultType), result,
2323 rhs, lhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002324 }
2325 return result;
2326 } else {
John Stilesd8ca6b62020-11-23 14:28:36 -05002327 fErrors.error(leftType.fOffset, "unsupported mixed-type expression");
Ethan Nicholas49465b42019-04-17 12:22:21 -04002328 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002329 }
2330 } else {
John Stiles2d4f9592020-10-30 10:29:12 -04002331 operandType = &this->getActualType(leftType);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002332 SkASSERT(*operandType == this->getActualType(rightType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002333 }
John Stiles45990502021-02-16 10:55:27 -05002334 switch (op.kind()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002335 case Token::Kind::TK_EQEQ: {
John Stiles9aeed132020-11-24 17:36:06 -05002336 if (operandType->isMatrix()) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002337 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002338 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002339 }
John Stiles4a7dc462020-11-25 11:08:08 -05002340 SkASSERT(resultType.isBoolean());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002341 const Type* tmpType;
John Stiles9aeed132020-11-24 17:36:06 -05002342 if (operandType->isVector()) {
John Stiles54e7c052021-01-11 14:22:36 -05002343 tmpType = &fContext.fTypes.fBool->toCompound(fContext,
2344 operandType->columns(),
2345 operandType->rows());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002346 } else {
2347 tmpType = &resultType;
2348 }
2349 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002350 SpvOpFOrdEqual, SpvOpIEqual,
2351 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002352 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002353 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002354 case Token::Kind::TK_NEQ:
John Stiles9aeed132020-11-24 17:36:06 -05002355 if (operandType->isMatrix()) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002356 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002357 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002358 }
John Stiles4a7dc462020-11-25 11:08:08 -05002359 [[fallthrough]];
2360 case Token::Kind::TK_LOGICALXOR:
2361 SkASSERT(resultType.isBoolean());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002362 const Type* tmpType;
John Stiles9aeed132020-11-24 17:36:06 -05002363 if (operandType->isVector()) {
John Stiles54e7c052021-01-11 14:22:36 -05002364 tmpType = &fContext.fTypes.fBool->toCompound(fContext,
2365 operandType->columns(),
2366 operandType->rows());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002367 } else {
2368 tmpType = &resultType;
2369 }
2370 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002371 SpvOpFOrdNotEqual, SpvOpINotEqual,
2372 SpvOpINotEqual, SpvOpLogicalNotEqual,
2373 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002374 *operandType, SpvOpAny, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002375 case Token::Kind::TK_GT:
John Stiles4a7dc462020-11-25 11:08:08 -05002376 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002377 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2378 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002379 SpvOpUGreaterThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002380 case Token::Kind::TK_LT:
John Stiles4a7dc462020-11-25 11:08:08 -05002381 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002382 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002383 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002384 case Token::Kind::TK_GTEQ:
John Stiles4a7dc462020-11-25 11:08:08 -05002385 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002386 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2387 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002388 SpvOpUGreaterThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002389 case Token::Kind::TK_LTEQ:
John Stiles4a7dc462020-11-25 11:08:08 -05002390 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002391 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2392 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002393 SpvOpULessThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002394 case Token::Kind::TK_PLUS:
John Stiles9aeed132020-11-24 17:36:06 -05002395 if (leftType.isMatrix() && rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002396 SkASSERT(leftType == rightType);
2397 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002398 SpvOpFAdd, SpvOpIAdd, out);
2399 }
Greg Daniel64773e62016-11-22 09:44:03 -05002400 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002401 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002402 case Token::Kind::TK_MINUS:
John Stiles9aeed132020-11-24 17:36:06 -05002403 if (leftType.isMatrix() && rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002404 SkASSERT(leftType == rightType);
2405 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002406 SpvOpFSub, SpvOpISub, out);
2407 }
Greg Daniel64773e62016-11-22 09:44:03 -05002408 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002409 SpvOpISub, SpvOpISub, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002410 case Token::Kind::TK_STAR:
John Stiles9aeed132020-11-24 17:36:06 -05002411 if (leftType.isMatrix() && rightType.isMatrix()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002412 // matrix multiply
2413 SpvId result = this->nextId();
2414 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2415 lhs, rhs, out);
2416 return result;
2417 }
Greg Daniel64773e62016-11-22 09:44:03 -05002418 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002419 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002420 case Token::Kind::TK_SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002421 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002422 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002423 case Token::Kind::TK_PERCENT:
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002424 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2425 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002426 case Token::Kind::TK_SHL:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002427 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2428 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2429 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002430 case Token::Kind::TK_SHR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002431 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2432 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2433 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002434 case Token::Kind::TK_BITWISEAND:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002435 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2436 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002437 case Token::Kind::TK_BITWISEOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002438 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2439 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002440 case Token::Kind::TK_BITWISEXOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002441 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2442 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002443 default:
John Stiles5570c512020-11-19 17:58:07 -05002444 fErrors.error(0, "unsupported token");
Ethan Nicholas49465b42019-04-17 12:22:21 -04002445 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002446 }
2447}
2448
Ethan Nicholas49465b42019-04-17 12:22:21 -04002449SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
John Stiles2d4f9592020-10-30 10:29:12 -04002450 const Expression& left = *b.left();
2451 const Expression& right = *b.right();
John Stiles45990502021-02-16 10:55:27 -05002452 Operator op = b.getOperator();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002453 // handle cases where we don't necessarily evaluate both LHS and RHS
John Stiles45990502021-02-16 10:55:27 -05002454 switch (op.kind()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002455 case Token::Kind::TK_EQ: {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002456 SpvId rhs = this->writeExpression(right, out);
2457 this->getLValue(left, out)->store(rhs, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002458 return rhs;
2459 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002460 case Token::Kind::TK_LOGICALAND:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002461 return this->writeLogicalAnd(b, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002462 case Token::Kind::TK_LOGICALOR:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002463 return this->writeLogicalOr(b, out);
2464 default:
2465 break;
2466 }
2467
2468 std::unique_ptr<LValue> lvalue;
2469 SpvId lhs;
John Stiles45990502021-02-16 10:55:27 -05002470 if (op.isAssignment()) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002471 lvalue = this->getLValue(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002472 lhs = lvalue->load(out);
2473 } else {
2474 lvalue = nullptr;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002475 lhs = this->writeExpression(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002476 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002477 SpvId rhs = this->writeExpression(right, out);
John Stiles45990502021-02-16 10:55:27 -05002478 SpvId result = this->writeBinaryExpression(left.type(), lhs, op.removeAssignment(),
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002479 right.type(), rhs, b.type(), out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002480 if (lvalue) {
2481 lvalue->store(result, out);
2482 }
2483 return result;
2484}
2485
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002486SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
John Stiles45990502021-02-16 10:55:27 -05002487 SkASSERT(a.getOperator().kind() == Token::Kind::TK_LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002488 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002489 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
John Stiles2d4f9592020-10-30 10:29:12 -04002490 SpvId lhs = this->writeExpression(*a.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002491 SpvId rhsLabel = this->nextId();
2492 SpvId end = this->nextId();
2493 SpvId lhsBlock = fCurrentBlock;
2494 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2495 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2496 this->writeLabel(rhsLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04002497 SpvId rhs = this->writeExpression(*a.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002498 SpvId rhsBlock = fCurrentBlock;
2499 this->writeInstruction(SpvOpBranch, end, out);
2500 this->writeLabel(end, out);
2501 SpvId result = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05002502 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fTypes.fBool), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002503 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002504 return result;
2505}
2506
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002507SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
John Stiles45990502021-02-16 10:55:27 -05002508 SkASSERT(o.getOperator().kind() == Token::Kind::TK_LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002509 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002510 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
John Stiles2d4f9592020-10-30 10:29:12 -04002511 SpvId lhs = this->writeExpression(*o.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002512 SpvId rhsLabel = this->nextId();
2513 SpvId end = this->nextId();
2514 SpvId lhsBlock = fCurrentBlock;
2515 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2516 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2517 this->writeLabel(rhsLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04002518 SpvId rhs = this->writeExpression(*o.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002519 SpvId rhsBlock = fCurrentBlock;
2520 this->writeInstruction(SpvOpBranch, end, out);
2521 this->writeLabel(end, out);
2522 SpvId result = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05002523 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fTypes.fBool), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002524 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002525 return result;
2526}
2527
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002528SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002529 const Type& type = t.type();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002530 SpvId test = this->writeExpression(*t.test(), out);
2531 if (t.ifTrue()->type().columns() == 1 &&
2532 t.ifTrue()->isCompileTimeConstant() &&
2533 t.ifFalse()->isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002534 // both true and false are constants, can just use OpSelect
2535 SpvId result = this->nextId();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002536 SpvId trueId = this->writeExpression(*t.ifTrue(), out);
2537 SpvId falseId = this->writeExpression(*t.ifFalse(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002538 this->writeInstruction(SpvOpSelect, this->getType(type), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002539 out);
2540 return result;
2541 }
Greg Daniel64773e62016-11-22 09:44:03 -05002542 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002543 // Adreno. Switched to storing the result in a temp variable as glslang does.
2544 SpvId var = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002545 this->writeInstruction(SpvOpVariable, this->getPointerType(type, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002546 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002547 SpvId trueLabel = this->nextId();
2548 SpvId falseLabel = this->nextId();
2549 SpvId end = this->nextId();
2550 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2551 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2552 this->writeLabel(trueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002553 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifTrue(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002554 this->writeInstruction(SpvOpBranch, end, out);
2555 this->writeLabel(falseLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002556 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifFalse(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002557 this->writeInstruction(SpvOpBranch, end, out);
2558 this->writeLabel(end, out);
2559 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002560 this->writeInstruction(SpvOpLoad, this->getType(type), result, var, out);
2561 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002562 return result;
2563}
2564
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002565SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002566 const Type& type = p.type();
John Stiles45990502021-02-16 10:55:27 -05002567 if (p.getOperator().kind() == Token::Kind::TK_MINUS) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002568 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002569 SpvId typeId = this->getType(type);
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002570 SpvId expr = this->writeExpression(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002571 if (is_float(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002572 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002573 } else if (is_signed(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002574 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2575 } else {
John Stileseada7bc2021-02-02 16:29:32 -05002576 SkDEBUGFAILF("unsupported prefix expression %s", p.description().c_str());
Brian Salomon23356442018-11-30 15:33:19 -05002577 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002578 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002579 return result;
2580 }
John Stiles45990502021-02-16 10:55:27 -05002581 switch (p.getOperator().kind()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002582 case Token::Kind::TK_PLUS:
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002583 return this->writeExpression(*p.operand(), out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002584 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002585 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002586 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
2587 SpvId result = this->writeBinaryOperation(type, type, lv->load(out), one,
Greg Daniel64773e62016-11-22 09:44:03 -05002588 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002589 out);
2590 lv->store(result, out);
2591 return result;
2592 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002593 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002594 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002595 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
2596 SpvId result = this->writeBinaryOperation(type, type, lv->load(out), one, SpvOpFSub,
2597 SpvOpISub, SpvOpISub, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002598 lv->store(result, out);
2599 return result;
2600 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002601 case Token::Kind::TK_LOGICALNOT: {
John Stiles4a7dc462020-11-25 11:08:08 -05002602 SkASSERT(p.operand()->type().isBoolean());
ethannicholasb3058bd2016-07-01 08:22:01 -07002603 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002604 this->writeInstruction(SpvOpLogicalNot, this->getType(type), result,
2605 this->writeExpression(*p.operand(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002606 return result;
2607 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002608 case Token::Kind::TK_BITWISENOT: {
ethannicholas5961bc92016-10-12 06:39:56 -07002609 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002610 this->writeInstruction(SpvOpNot, this->getType(type), result,
2611 this->writeExpression(*p.operand(), out), out);
ethannicholas5961bc92016-10-12 06:39:56 -07002612 return result;
2613 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002614 default:
John Stileseada7bc2021-02-02 16:29:32 -05002615 SkDEBUGFAILF("unsupported prefix expression: %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002616 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002617 }
2618}
2619
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002620SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002621 const Type& type = p.type();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002622 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002623 SpvId result = lv->load(out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002624 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
John Stiles45990502021-02-16 10:55:27 -05002625 switch (p.getOperator().kind()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002626 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002627 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002628 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2629 lv->store(temp, out);
2630 return result;
2631 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002632 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002633 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002634 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2635 lv->store(temp, out);
2636 return result;
2637 }
2638 default:
John Stileseada7bc2021-02-02 16:29:32 -05002639 SkDEBUGFAILF("unsupported postfix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002640 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002641 }
2642}
2643
ethannicholasf789b382016-08-03 12:43:36 -07002644SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
Ethan Nicholas59d660c2020-09-28 09:18:15 -04002645 if (b.value()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002646 if (fBoolTrue == 0) {
2647 fBoolTrue = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002648 this->writeInstruction(SpvOpConstantTrue, this->getType(b.type()), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002649 fConstantBuffer);
2650 }
2651 return fBoolTrue;
2652 } else {
2653 if (fBoolFalse == 0) {
2654 fBoolFalse = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002655 this->writeInstruction(SpvOpConstantFalse, this->getType(b.type()), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002656 fConstantBuffer);
2657 }
2658 return fBoolFalse;
2659 }
2660}
2661
ethannicholasf789b382016-08-03 12:43:36 -07002662SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
John Stilesbdc3d3c2021-01-06 18:41:40 -05002663 SPIRVNumberConstant key{i.value(), i.type().numberKind()};
John Stilesacb091f2021-01-06 11:57:58 -05002664 auto [iter, newlyCreated] = fNumberConstants.insert({key, (SpvId)-1});
2665 if (newlyCreated) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002666 SpvId result = this->nextId();
John Stilesacb091f2021-01-06 11:57:58 -05002667 this->writeInstruction(SpvOpConstant, this->getType(i.type()), result, (SpvId) i.value(),
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002668 fConstantBuffer);
John Stilesacb091f2021-01-06 11:57:58 -05002669 iter->second = result;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002670 }
John Stilesacb091f2021-01-06 11:57:58 -05002671 return iter->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002672}
2673
ethannicholasf789b382016-08-03 12:43:36 -07002674SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
John Stilesbdc3d3c2021-01-06 18:41:40 -05002675 // Convert the float literal into its bit-representation.
2676 float value = f.value();
2677 uint32_t valueBits;
2678 static_assert(sizeof(valueBits) == sizeof(value));
2679 memcpy(&valueBits, &value, sizeof(value));
2680
2681 SPIRVNumberConstant key{valueBits, f.type().numberKind()};
John Stilesacb091f2021-01-06 11:57:58 -05002682 auto [iter, newlyCreated] = fNumberConstants.insert({key, (SpvId)-1});
2683 if (newlyCreated) {
John Stiles8c578662020-06-01 15:32:47 +00002684 SpvId result = this->nextId();
John Stilesbdc3d3c2021-01-06 18:41:40 -05002685 this->writeInstruction(SpvOpConstant, this->getType(f.type()), result, (SpvId) valueBits,
John Stiles8c578662020-06-01 15:32:47 +00002686 fConstantBuffer);
John Stilesacb091f2021-01-06 11:57:58 -05002687 iter->second = result;
John Stiles8c578662020-06-01 15:32:47 +00002688 }
John Stilesacb091f2021-01-06 11:57:58 -05002689 return iter->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002690}
2691
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002692SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002693 SpvId result = fFunctionMap[&f];
John Stilesb5db4822021-01-21 13:04:40 -05002694 SpvId returnTypeId = this->getType(f.returnType());
2695 SpvId functionTypeId = this->getFunctionType(f);
2696 this->writeInstruction(SpvOpFunction, returnTypeId, result,
2697 SpvFunctionControlMaskNone, functionTypeId, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04002698 this->writeInstruction(SpvOpName, result, f.name(), fNameBuffer);
Brian Osman5bf3e202020-10-13 10:34:18 -04002699 const std::vector<const Variable*>& parameters = f.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -04002700 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002701 SpvId id = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -04002702 fVariableMap[parameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002703 SpvId type;
Ethan Nicholased84b732020-10-08 11:45:44 -04002704 type = this->getPointerType(parameters[i]->type(), SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002705 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2706 }
2707 return result;
2708}
2709
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002710SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2711 fVariableBuffer.reset();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002712 SpvId result = this->writeFunctionStart(f.declaration(), out);
Ethan Nicholas7fb39362020-12-16 15:25:19 -05002713 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002714 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002715 StringStream bodyBuffer;
John Stiles0693fb82021-01-22 18:27:52 -05002716 this->writeBlock(f.body()->as<Block>(), bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002717 write_stringstream(fVariableBuffer, out);
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002718 if (f.declaration().name() == "main") {
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002719 write_stringstream(fGlobalInitializersBuffer, out);
2720 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002721 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002722 if (fCurrentBlock) {
John Stiles54e7c052021-01-11 14:22:36 -05002723 if (f.declaration().returnType() == *fContext.fTypes.fVoid) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002724 this->writeInstruction(SpvOpReturn, out);
2725 } else {
2726 this->writeInstruction(SpvOpUnreachable, out);
2727 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002728 }
2729 this->writeInstruction(SpvOpFunctionEnd, out);
2730 return result;
2731}
2732
2733void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2734 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002735 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002736 fDecorationBuffer);
2737 }
2738 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002739 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002740 fDecorationBuffer);
2741 }
2742 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002743 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002744 fDecorationBuffer);
2745 }
2746 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002747 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002748 fDecorationBuffer);
2749 }
Greg Daniel64773e62016-11-22 09:44:03 -05002750 if (layout.fInputAttachmentIndex >= 0) {
2751 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2752 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002753 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002754 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002755 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002756 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002757 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002758 fDecorationBuffer);
2759 }
2760}
2761
2762void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2763 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002764 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002765 layout.fLocation, fDecorationBuffer);
2766 }
2767 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002768 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002769 layout.fBinding, fDecorationBuffer);
2770 }
2771 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002772 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002773 layout.fIndex, fDecorationBuffer);
2774 }
2775 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002776 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002777 layout.fSet, fDecorationBuffer);
2778 }
Greg Daniel64773e62016-11-22 09:44:03 -05002779 if (layout.fInputAttachmentIndex >= 0) {
2780 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2781 layout.fInputAttachmentIndex, fDecorationBuffer);
2782 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002783 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002784 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002785 layout.fBuiltin, fDecorationBuffer);
2786 }
2787}
2788
Brian Osman2a4c0fb2021-01-22 13:41:40 -05002789MemoryLayout SPIRVCodeGenerator::memoryLayoutForVariable(const Variable& v) const {
Brian Osman2a4c0fb2021-01-22 13:41:40 -05002790 bool pushConstant = ((v.modifiers().fLayout.fFlags & Layout::kPushConstant_Flag) != 0);
Brian Osman58ee8982021-02-18 15:39:38 -05002791 return pushConstant ? MemoryLayout(MemoryLayout::k430_Standard) : fDefaultLayout;
Brian Osman2a4c0fb2021-01-22 13:41:40 -05002792}
2793
Ethan Nicholas81d15112018-07-13 12:48:50 -04002794static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2795 switch (m.fLayout.fPrimitive) {
2796 case Layout::kPoints_Primitive:
2797 *outSkInCount = 1;
2798 break;
2799 case Layout::kLines_Primitive:
2800 *outSkInCount = 2;
2801 break;
2802 case Layout::kLinesAdjacency_Primitive:
2803 *outSkInCount = 4;
2804 break;
2805 case Layout::kTriangles_Primitive:
2806 *outSkInCount = 3;
2807 break;
2808 case Layout::kTrianglesAdjacency_Primitive:
2809 *outSkInCount = 6;
2810 break;
2811 default:
2812 return;
2813 }
2814}
2815
Stephen White88574972020-06-23 19:09:29 -04002816SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf, bool appendRTHeight) {
Brian Osman2a4c0fb2021-01-22 13:41:40 -05002817 MemoryLayout memoryLayout = this->memoryLayoutForVariable(intf.variable());
ethannicholasb3058bd2016-07-01 08:22:01 -07002818 SpvId result = this->nextId();
John Stilesad2d4942020-12-11 16:55:58 -05002819 std::unique_ptr<Type> rtHeightStructType;
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002820 const Type* type = &intf.variable().type();
John Stiles21f5f452020-11-30 09:57:59 -05002821 if (!MemoryLayout::LayoutIsSupported(*type)) {
John Stiles0023c0c2020-11-16 13:32:18 -05002822 fErrors.error(type->fOffset, "type '" + type->name() + "' is not permitted here");
2823 return this->nextId();
2824 }
John Stiles9485b552021-01-27 11:47:00 -05002825 SpvStorageClass_ storageClass = get_storage_class(intf.variable(), SpvStorageClassFunction);
Stephen White88574972020-06-23 19:09:29 -04002826 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Greg Daniele6ab9982018-08-22 13:56:32 +00002827 SkASSERT(fRTHeightStructId == (SpvId) -1);
2828 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002829 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002830 fRTHeightStructId = result;
2831 fRTHeightFieldIndex = fields.size();
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002832 fRTHeightStorageClass = storageClass;
John Stilesad2d4942020-12-11 16:55:58 -05002833 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME),
John Stiles54e7c052021-01-11 14:22:36 -05002834 fContext.fTypes.fFloat.get());
John Stilesad2d4942020-12-11 16:55:58 -05002835 rtHeightStructType = Type::MakeStructType(type->fOffset, type->name(), std::move(fields));
2836 type = rtHeightStructType.get();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002837 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002838 SpvId typeId;
John Stiles9485b552021-01-27 11:47:00 -05002839 const Modifiers& intfModifiers = intf.variable().modifiers();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002840 if (intfModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osman133724c2020-10-28 14:14:39 -04002841 for (const ProgramElement* e : fProgram.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04002842 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04002843 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholas81d15112018-07-13 12:48:50 -04002844 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002845 }
2846 }
John Stilesad2d4942020-12-11 16:55:58 -05002847 typeId = this->getType(
2848 *Type::MakeArrayType("sk_in", intf.variable().type().componentType(), fSkInCount),
2849 memoryLayout);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002850 } else {
2851 typeId = this->getType(*type, memoryLayout);
2852 }
Brian Osman58ee8982021-02-18 15:39:38 -05002853 if (intfModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002854 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002855 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002856 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002857 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002858 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002859 Layout layout = intfModifiers.fLayout;
2860 if (intfModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002861 layout.fSet = 0;
2862 }
2863 this->writeLayout(layout, result);
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002864 fVariableMap[&intf.variable()] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002865 return result;
2866}
2867
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002868void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002869 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2870}
2871
2872void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2873 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002874 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2875 }
2876}
2877
John Stiles9485b552021-01-27 11:47:00 -05002878static bool is_dead(const Variable& var, const ProgramUsage* usage) {
Brian Osman010ce6a2020-10-19 16:34:10 -04002879 ProgramUsage::VariableCounts counts = usage->get(var);
2880 if (counts.fRead || counts.fWrite) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002881 return false;
2882 }
2883 // not entirely sure what the rules are for when it's safe to elide interface variables, but it
2884 // causes various problems to elide some of them even when dead. But it also causes problems
2885 // *not* to elide sk_SampleMask when it's not being used.
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002886 if (!(var.modifiers().fFlags & (Modifiers::kIn_Flag |
2887 Modifiers::kOut_Flag |
Brian Osman58ee8982021-02-18 15:39:38 -05002888 Modifiers::kUniform_Flag))) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002889 return true;
2890 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002891 return var.modifiers().fLayout.fBuiltin == SK_SAMPLEMASK_BUILTIN;
Chris Dalton2284aab2019-11-15 11:02:24 -07002892}
2893
John Stilesdbd4e6f2021-02-16 13:29:15 -05002894void SPIRVCodeGenerator::writeGlobalVar(ProgramKind kind, const VarDeclaration& varDecl) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002895 const Variable& var = varDecl.var();
John Stiles0ca2f592021-01-27 10:58:10 -05002896 // 9999 is a sentinel value used in our built-in modules that causes us to ignore these
2897 // declarations, beyond adding them to the symbol table.
2898 constexpr int kBuiltinIgnore = 9999;
2899 if (var.modifiers().fLayout.fBuiltin == kBuiltinIgnore) {
Brian Osmanc0213602020-10-06 14:43:32 -04002900 return;
2901 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002902 if (var.modifiers().fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
John Stilesdbd4e6f2021-02-16 13:29:15 -05002903 kind != ProgramKind::kFragment) {
John Stiles270cec22021-02-17 12:59:36 -05002904 SkASSERT(!fProgram.fConfig->fSettings.fFragColorIsInOut);
Brian Osmanc0213602020-10-06 14:43:32 -04002905 return;
2906 }
Brian Osman010ce6a2020-10-19 16:34:10 -04002907 if (is_dead(var, fProgram.fUsage.get())) {
Brian Osmanc0213602020-10-06 14:43:32 -04002908 return;
2909 }
John Stiles0de76f72021-01-29 09:19:39 -05002910 SpvStorageClass_ storageClass = get_storage_class(var, SpvStorageClassPrivate);
John Stilese40d1662021-01-29 10:08:50 -05002911 if (storageClass == SpvStorageClassUniform) {
2912 // Top-level uniforms are emitted in writeUniformBuffer.
2913 fTopLevelUniforms.push_back(&varDecl);
2914 return;
2915 }
2916 const Type& type = var.type();
John Stilesd8fc95d2021-01-26 16:22:53 -05002917 Layout layout = var.modifiers().fLayout;
John Stilese40d1662021-01-29 10:08:50 -05002918 if (layout.fSet < 0 && storageClass == SpvStorageClassUniformConstant) {
John Stiles270cec22021-02-17 12:59:36 -05002919 layout.fSet = fProgram.fConfig->fSettings.fDefaultUniformSet;
Brian Osmanc0213602020-10-06 14:43:32 -04002920 }
2921 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002922 fVariableMap[&var] = id;
Brian Osmanc0213602020-10-06 14:43:32 -04002923 SpvId typeId;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002924 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osmanc0213602020-10-06 14:43:32 -04002925 typeId = this->getPointerType(
John Stilesad2d4942020-12-11 16:55:58 -05002926 *Type::MakeArrayType("sk_in", type.componentType(), fSkInCount),
Brian Osmanc0213602020-10-06 14:43:32 -04002927 storageClass);
2928 } else {
2929 typeId = this->getPointerType(type, storageClass);
2930 }
2931 this->writeInstruction(SpvOpVariable, typeId, id, storageClass, fConstantBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002932 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002933 this->writePrecisionModifier(type, id);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002934 if (varDecl.value()) {
Brian Osmanc0213602020-10-06 14:43:32 -04002935 SkASSERT(!fCurrentBlock);
2936 fCurrentBlock = -1;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002937 SpvId value = this->writeExpression(*varDecl.value(), fGlobalInitializersBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002938 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
2939 fCurrentBlock = 0;
2940 }
John Stilesd8fc95d2021-01-26 16:22:53 -05002941 this->writeLayout(layout, id);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002942 if (var.modifiers().fFlags & Modifiers::kFlat_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002943 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2944 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002945 if (var.modifiers().fFlags & Modifiers::kNoPerspective_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002946 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2947 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002948 }
2949}
2950
Brian Osmanc0213602020-10-06 14:43:32 -04002951void SPIRVCodeGenerator::writeVarDeclaration(const VarDeclaration& varDecl, OutputStream& out) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002952 const Variable& var = varDecl.var();
Brian Osmanc0213602020-10-06 14:43:32 -04002953 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002954 fVariableMap[&var] = id;
2955 SpvId type = this->getPointerType(var.type(), SpvStorageClassFunction);
Brian Osmanc0213602020-10-06 14:43:32 -04002956 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002957 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
2958 if (varDecl.value()) {
2959 SpvId value = this->writeExpression(*varDecl.value(), out);
Brian Osmanc0213602020-10-06 14:43:32 -04002960 this->writeInstruction(SpvOpStore, id, value, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002961 }
2962}
2963
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002964void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002965 switch (s.kind()) {
John Stiles98c1f822020-09-09 14:18:53 -04002966 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04002967 case Statement::Kind::kNop:
Ethan Nicholascb670962017-04-20 19:31:52 -04002968 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002969 case Statement::Kind::kBlock:
John Stiles0693fb82021-01-22 18:27:52 -05002970 this->writeBlock(s.as<Block>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002971 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002972 case Statement::Kind::kExpression:
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04002973 this->writeExpression(*s.as<ExpressionStatement>().expression(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002974 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002975 case Statement::Kind::kReturn:
John Stiles26f98502020-08-18 09:30:51 -04002976 this->writeReturnStatement(s.as<ReturnStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002977 break;
Brian Osmanc0213602020-10-06 14:43:32 -04002978 case Statement::Kind::kVarDeclaration:
2979 this->writeVarDeclaration(s.as<VarDeclaration>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002980 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002981 case Statement::Kind::kIf:
John Stiles26f98502020-08-18 09:30:51 -04002982 this->writeIfStatement(s.as<IfStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002983 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002984 case Statement::Kind::kFor:
John Stiles26f98502020-08-18 09:30:51 -04002985 this->writeForStatement(s.as<ForStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002986 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002987 case Statement::Kind::kDo:
John Stiles26f98502020-08-18 09:30:51 -04002988 this->writeDoStatement(s.as<DoStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002989 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002990 case Statement::Kind::kSwitch:
John Stiles26f98502020-08-18 09:30:51 -04002991 this->writeSwitchStatement(s.as<SwitchStatement>(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002992 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002993 case Statement::Kind::kBreak:
ethannicholasb3058bd2016-07-01 08:22:01 -07002994 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2995 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002996 case Statement::Kind::kContinue:
ethannicholasb3058bd2016-07-01 08:22:01 -07002997 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2998 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002999 case Statement::Kind::kDiscard:
ethannicholasb3058bd2016-07-01 08:22:01 -07003000 this->writeInstruction(SpvOpKill, out);
3001 break;
3002 default:
John Stileseada7bc2021-02-02 16:29:32 -05003003 SkDEBUGFAILF("unsupported statement: %s", s.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05003004 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003005 }
3006}
3007
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003008void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04003009 for (const std::unique_ptr<Statement>& stmt : b.children()) {
3010 this->writeStatement(*stmt, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003011 }
3012}
3013
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003014void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04003015 SpvId test = this->writeExpression(*stmt.test(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003016 SpvId ifTrue = this->nextId();
3017 SpvId ifFalse = this->nextId();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04003018 if (stmt.ifFalse()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003019 SpvId end = this->nextId();
3020 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3021 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
3022 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04003023 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003024 if (fCurrentBlock) {
3025 this->writeInstruction(SpvOpBranch, end, out);
3026 }
3027 this->writeLabel(ifFalse, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04003028 this->writeStatement(*stmt.ifFalse(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003029 if (fCurrentBlock) {
3030 this->writeInstruction(SpvOpBranch, end, out);
3031 }
3032 this->writeLabel(end, out);
3033 } else {
3034 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
3035 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
3036 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04003037 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003038 if (fCurrentBlock) {
3039 this->writeInstruction(SpvOpBranch, ifFalse, out);
3040 }
3041 this->writeLabel(ifFalse, out);
3042 }
3043}
3044
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003045void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003046 if (f.initializer()) {
3047 this->writeStatement(*f.initializer(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003048 }
3049 SpvId header = this->nextId();
3050 SpvId start = this->nextId();
3051 SpvId body = this->nextId();
3052 SpvId next = this->nextId();
3053 fContinueTarget.push(next);
3054 SpvId end = this->nextId();
3055 fBreakTarget.push(end);
3056 this->writeInstruction(SpvOpBranch, header, out);
3057 this->writeLabel(header, out);
3058 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07003059 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003060 this->writeLabel(start, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003061 if (f.test()) {
3062 SpvId test = this->writeExpression(*f.test(), out);
ethannicholas22f939e2016-10-13 13:25:34 -07003063 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
Ethan Nicholas7fb39362020-12-16 15:25:19 -05003064 } else {
3065 this->writeInstruction(SpvOpBranch, body, out);
ethannicholas22f939e2016-10-13 13:25:34 -07003066 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003067 this->writeLabel(body, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003068 this->writeStatement(*f.statement(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003069 if (fCurrentBlock) {
3070 this->writeInstruction(SpvOpBranch, next, out);
3071 }
3072 this->writeLabel(next, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003073 if (f.next()) {
3074 this->writeExpression(*f.next(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003075 }
3076 this->writeInstruction(SpvOpBranch, header, out);
3077 this->writeLabel(end, out);
3078 fBreakTarget.pop();
3079 fContinueTarget.pop();
3080}
3081
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003082void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003083 SpvId header = this->nextId();
3084 SpvId start = this->nextId();
3085 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003086 SpvId continueTarget = this->nextId();
3087 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003088 SpvId end = this->nextId();
3089 fBreakTarget.push(end);
3090 this->writeInstruction(SpvOpBranch, header, out);
3091 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003092 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003093 this->writeInstruction(SpvOpBranch, start, out);
3094 this->writeLabel(start, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003095 this->writeStatement(*d.statement(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003096 if (fCurrentBlock) {
3097 this->writeInstruction(SpvOpBranch, next, out);
3098 }
3099 this->writeLabel(next, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003100 SpvId test = this->writeExpression(*d.test(), out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003101 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
3102 this->writeLabel(continueTarget, out);
3103 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003104 this->writeLabel(end, out);
3105 fBreakTarget.pop();
3106 fContinueTarget.pop();
3107}
3108
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003109void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04003110 SpvId value = this->writeExpression(*s.value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003111 std::vector<SpvId> labels;
3112 SpvId end = this->nextId();
3113 SpvId defaultLabel = end;
3114 fBreakTarget.push(end);
3115 int size = 3;
John Stiles2d4f9592020-10-30 10:29:12 -04003116 auto& cases = s.cases();
3117 for (const std::unique_ptr<SwitchCase>& c : cases) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003118 SpvId label = this->nextId();
3119 labels.push_back(label);
John Stiles2d4f9592020-10-30 10:29:12 -04003120 if (c->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003121 size += 2;
3122 } else {
3123 defaultLabel = label;
3124 }
3125 }
3126 labels.push_back(end);
3127 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3128 this->writeOpCode(SpvOpSwitch, size, out);
3129 this->writeWord(value, out);
3130 this->writeWord(defaultLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04003131 for (size_t i = 0; i < cases.size(); ++i) {
3132 if (!cases[i]->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003133 continue;
3134 }
John Stiles2d4f9592020-10-30 10:29:12 -04003135 this->writeWord(cases[i]->value()->as<IntLiteral>().value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003136 this->writeWord(labels[i], out);
3137 }
John Stiles2d4f9592020-10-30 10:29:12 -04003138 for (size_t i = 0; i < cases.size(); ++i) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003139 this->writeLabel(labels[i], out);
John Stiles2d4f9592020-10-30 10:29:12 -04003140 for (const auto& stmt : cases[i]->statements()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003141 this->writeStatement(*stmt, out);
3142 }
3143 if (fCurrentBlock) {
3144 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3145 }
3146 }
3147 this->writeLabel(end, out);
3148 fBreakTarget.pop();
3149}
3150
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003151void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003152 if (r.expression()) {
3153 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.expression(), out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003154 out);
3155 } else {
3156 this->writeInstruction(SpvOpReturn, out);
3157 }
3158}
3159
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003160void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
John Stiles270cec22021-02-17 12:59:36 -05003161 SkASSERT(fProgram.fConfig->fKind == ProgramKind::kGeometry);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003162 int invocations = 1;
Brian Osman133724c2020-10-28 14:14:39 -04003163 for (const ProgramElement* e : fProgram.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003164 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04003165 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003166 if (m.fFlags & Modifiers::kIn_Flag) {
3167 if (m.fLayout.fInvocations != -1) {
3168 invocations = m.fLayout.fInvocations;
3169 }
3170 SpvId input;
3171 switch (m.fLayout.fPrimitive) {
3172 case Layout::kPoints_Primitive:
3173 input = SpvExecutionModeInputPoints;
3174 break;
3175 case Layout::kLines_Primitive:
3176 input = SpvExecutionModeInputLines;
3177 break;
3178 case Layout::kLinesAdjacency_Primitive:
3179 input = SpvExecutionModeInputLinesAdjacency;
3180 break;
3181 case Layout::kTriangles_Primitive:
3182 input = SpvExecutionModeTriangles;
3183 break;
3184 case Layout::kTrianglesAdjacency_Primitive:
3185 input = SpvExecutionModeInputTrianglesAdjacency;
3186 break;
3187 default:
3188 input = 0;
3189 break;
3190 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003191 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003192 if (input) {
3193 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3194 }
3195 } else if (m.fFlags & Modifiers::kOut_Flag) {
3196 SpvId output;
3197 switch (m.fLayout.fPrimitive) {
3198 case Layout::kPoints_Primitive:
3199 output = SpvExecutionModeOutputPoints;
3200 break;
3201 case Layout::kLineStrip_Primitive:
3202 output = SpvExecutionModeOutputLineStrip;
3203 break;
3204 case Layout::kTriangleStrip_Primitive:
3205 output = SpvExecutionModeOutputTriangleStrip;
3206 break;
3207 default:
3208 output = 0;
3209 break;
3210 }
3211 if (output) {
3212 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3213 }
3214 if (m.fLayout.fMaxVertices != -1) {
3215 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3216 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3217 out);
3218 }
3219 }
3220 }
3221 }
3222 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3223 invocations, out);
3224}
3225
John Stilese40d1662021-01-29 10:08:50 -05003226// Given any function, returns the top-level symbol table (OUTSIDE of the function's scope).
3227static std::shared_ptr<SymbolTable> get_top_level_symbol_table(const FunctionDeclaration& anyFunc) {
3228 return anyFunc.definition()->body()->as<Block>().symbolTable()->fParent;
3229}
3230
John Stiles4d6310a2021-01-26 19:58:22 -05003231SPIRVCodeGenerator::EntrypointAdapter SPIRVCodeGenerator::writeEntrypointAdapter(
3232 const FunctionDeclaration& main) {
3233 // Our goal is to synthesize a tiny helper function which looks like this:
3234 // void _entrypoint() { sk_FragColor = main(); }
3235
3236 // Fish a symbol table out of main().
John Stilese40d1662021-01-29 10:08:50 -05003237 std::shared_ptr<SymbolTable> symbolTable = get_top_level_symbol_table(main);
John Stiles4d6310a2021-01-26 19:58:22 -05003238
3239 // Get `sk_FragColor` as a writable reference.
3240 const Symbol* skFragColorSymbol = (*symbolTable)["sk_FragColor"];
3241 SkASSERT(skFragColorSymbol);
3242 const Variable& skFragColorVar = skFragColorSymbol->as<Variable>();
3243 auto skFragColorRef = std::make_unique<VariableReference>(/*offset=*/-1, &skFragColorVar,
3244 VariableReference::RefKind::kWrite);
3245 // Synthesize a call to the `main()` function.
3246 if (main.returnType() != skFragColorRef->type()) {
3247 fErrors.error(main.fOffset, "SPIR-V does not support returning '" +
3248 main.returnType().description() + "' from main()");
3249 return {};
3250 }
3251 auto callMainFn = std::make_unique<FunctionCall>(/*offset=*/-1, &main.returnType(), &main,
3252 /*arguments=*/ExpressionArray{});
3253
3254 // Synthesize `skFragColor = main()` as a BinaryExpression.
3255 auto assignmentStmt = std::make_unique<ExpressionStatement>(std::make_unique<BinaryExpression>(
3256 /*offset=*/-1,
3257 std::move(skFragColorRef),
3258 Token::Kind::TK_EQ,
3259 std::move(callMainFn),
3260 &main.returnType()));
3261
3262 // Function bodies are always wrapped in a Block.
3263 StatementArray entrypointStmts;
3264 entrypointStmts.push_back(std::move(assignmentStmt));
3265 auto entrypointBlock = std::make_unique<Block>(/*offset=*/-1, std::move(entrypointStmts),
3266 symbolTable, /*isScope=*/true);
3267 // Declare an entrypoint function.
3268 EntrypointAdapter adapter;
3269 adapter.fLayout = {};
3270 adapter.fModifiers = Modifiers{adapter.fLayout, Modifiers::kHasSideEffects_Flag};
3271 adapter.entrypointDecl =
3272 std::make_unique<FunctionDeclaration>(/*offset=*/-1,
3273 &adapter.fModifiers,
3274 "_entrypoint",
3275 /*parameters=*/std::vector<const Variable*>{},
3276 /*returnType=*/fContext.fTypes.fVoid.get(),
3277 /*builtin=*/false);
3278 // Define it.
3279 adapter.entrypointDef =
3280 std::make_unique<FunctionDefinition>(/*offset=*/-1, adapter.entrypointDecl.get(),
3281 /*builtin=*/false,
3282 /*body=*/std::move(entrypointBlock));
3283
3284 adapter.entrypointDecl->setDefinition(adapter.entrypointDef.get());
3285 return adapter;
3286}
3287
John Stilese40d1662021-01-29 10:08:50 -05003288void SPIRVCodeGenerator::writeUniformBuffer(std::shared_ptr<SymbolTable> topLevelSymbolTable) {
3289 SkASSERT(!fTopLevelUniforms.empty());
3290 static constexpr char kUniformBufferName[] = "_UniformBuffer";
3291
3292 // Convert the list of top-level uniforms into a matching struct named _UniformBuffer, and build
3293 // a lookup table of variables to UniformBuffer field indices.
3294 std::vector<Type::Field> fields;
3295 fields.reserve(fTopLevelUniforms.size());
3296 fTopLevelUniformMap.reserve(fTopLevelUniforms.size());
3297 for (const VarDeclaration* topLevelUniform : fTopLevelUniforms) {
3298 const Variable* var = &topLevelUniform->var();
3299 fTopLevelUniformMap[var] = (int)fields.size();
3300 fields.emplace_back(var->modifiers(), var->name(), &var->type());
3301 }
3302 fUniformBuffer.fStruct = Type::MakeStructType(/*offset=*/-1, kUniformBufferName,
3303 std::move(fields));
3304
3305 // Create a global variable to contain this struct.
3306 Layout layout;
John Stiles270cec22021-02-17 12:59:36 -05003307 layout.fBinding = fProgram.fConfig->fSettings.fDefaultUniformBinding;
3308 layout.fSet = fProgram.fConfig->fSettings.fDefaultUniformSet;
John Stilese40d1662021-01-29 10:08:50 -05003309 Modifiers modifiers{layout, Modifiers::kUniform_Flag};
3310
3311 fUniformBuffer.fInnerVariable = std::make_unique<Variable>(
3312 /*offset=*/-1, fProgram.fModifiers->addToPool(modifiers), kUniformBufferName,
3313 fUniformBuffer.fStruct.get(), /*builtin=*/false, Variable::Storage::kGlobal);
3314
3315 // Create an interface block object for this global variable.
3316 fUniformBuffer.fInterfaceBlock = std::make_unique<InterfaceBlock>(
3317 /*offset=*/-1, fUniformBuffer.fInnerVariable.get(), kUniformBufferName,
3318 kUniformBufferName, /*arraySize=*/0, topLevelSymbolTable);
3319
3320 // Generate an interface block and hold onto its ID.
3321 fUniformBufferId = this->writeInterfaceBlock(*fUniformBuffer.fInterfaceBlock);
3322}
3323
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003324void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003325 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003326 StringStream body;
John Stiles4d6310a2021-01-26 19:58:22 -05003327 // Assign SpvIds to functions.
3328 const FunctionDeclaration* main = nullptr;
Brian Osman133724c2020-10-28 14:14:39 -04003329 for (const ProgramElement* e : program.elements()) {
John Stiles4d6310a2021-01-26 19:58:22 -05003330 if (e->is<FunctionDefinition>()) {
3331 const FunctionDefinition& funcDef = e->as<FunctionDefinition>();
3332 const FunctionDeclaration& funcDecl = funcDef.declaration();
3333 fFunctionMap[&funcDecl] = this->nextId();
3334 if (funcDecl.name() == "main") {
3335 main = &funcDecl;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003336 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003337 }
3338 }
John Stiles4d6310a2021-01-26 19:58:22 -05003339 // Make sure we have a main() function.
3340 if (!main) {
3341 fErrors.error(/*offset=*/0, "program does not contain a main() function");
3342 return;
3343 }
3344 // Emit interface blocks.
3345 std::set<SpvId> interfaceVars;
Brian Osman133724c2020-10-28 14:14:39 -04003346 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003347 if (e->is<InterfaceBlock>()) {
Brian Osman1f8f5752020-10-28 14:46:21 -04003348 const InterfaceBlock& intf = e->as<InterfaceBlock>();
ethannicholasb3058bd2016-07-01 08:22:01 -07003349 SpvId id = this->writeInterfaceBlock(intf);
Brian Osman1f8f5752020-10-28 14:46:21 -04003350
3351 const Modifiers& modifiers = intf.variable().modifiers();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003352 if (((modifiers.fFlags & Modifiers::kIn_Flag) ||
John Stiles4d6310a2021-01-26 19:58:22 -05003353 (modifiers.fFlags & Modifiers::kOut_Flag)) &&
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003354 modifiers.fLayout.fBuiltin == -1 &&
Brian Osman010ce6a2020-10-19 16:34:10 -04003355 !is_dead(intf.variable(), fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003356 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003357 }
3358 }
3359 }
John Stiles4d6310a2021-01-26 19:58:22 -05003360 // Emit global variable declarations.
Brian Osman133724c2020-10-28 14:14:39 -04003361 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003362 if (e->is<GlobalVarDeclaration>()) {
John Stiles270cec22021-02-17 12:59:36 -05003363 this->writeGlobalVar(program.fConfig->fKind,
John Stilese40d1662021-01-29 10:08:50 -05003364 e->as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>());
ethannicholasb3058bd2016-07-01 08:22:01 -07003365 }
3366 }
John Stilese40d1662021-01-29 10:08:50 -05003367 // Emit top-level uniforms into a dedicated uniform buffer.
3368 if (!fTopLevelUniforms.empty()) {
3369 this->writeUniformBuffer(get_top_level_symbol_table(*main));
3370 }
John Stiles4d6310a2021-01-26 19:58:22 -05003371 // If main() returns a half4, synthesize a tiny entrypoint function which invokes the real
3372 // main() and stores the result into sk_FragColor.
3373 EntrypointAdapter adapter;
3374 if (main->returnType() == *fContext.fTypes.fHalf4) {
3375 adapter = this->writeEntrypointAdapter(*main);
3376 if (adapter.entrypointDecl) {
3377 fFunctionMap[adapter.entrypointDecl.get()] = this->nextId();
3378 this->writeFunction(*adapter.entrypointDef, body);
3379 main = adapter.entrypointDecl.get();
3380 }
3381 }
3382 // Emit all the functions.
Brian Osman133724c2020-10-28 14:14:39 -04003383 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003384 if (e->is<FunctionDefinition>()) {
3385 this->writeFunction(e->as<FunctionDefinition>(), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003386 }
3387 }
John Stiles4d6310a2021-01-26 19:58:22 -05003388 // Add global in/out variables to the list of interface variables.
ethannicholasb3058bd2016-07-01 08:22:01 -07003389 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003390 const Variable* var = entry.first;
Ethan Nicholas453f67f2020-10-09 10:43:45 -04003391 if (var->storage() == Variable::Storage::kGlobal &&
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003392 ((var->modifiers().fFlags & Modifiers::kIn_Flag) ||
Brian Osman010ce6a2020-10-19 16:34:10 -04003393 (var->modifiers().fFlags & Modifiers::kOut_Flag)) &&
3394 !is_dead(*var, fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003395 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003396 }
3397 }
3398 this->writeCapabilities(out);
3399 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3400 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003401 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->name().fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003402 (int32_t) interfaceVars.size(), out);
John Stiles270cec22021-02-17 12:59:36 -05003403 switch (program.fConfig->fKind) {
John Stilesdbd4e6f2021-02-16 13:29:15 -05003404 case ProgramKind::kVertex:
ethannicholasb3058bd2016-07-01 08:22:01 -07003405 this->writeWord(SpvExecutionModelVertex, out);
3406 break;
John Stilesdbd4e6f2021-02-16 13:29:15 -05003407 case ProgramKind::kFragment:
ethannicholasb3058bd2016-07-01 08:22:01 -07003408 this->writeWord(SpvExecutionModelFragment, out);
3409 break;
John Stilesdbd4e6f2021-02-16 13:29:15 -05003410 case ProgramKind::kGeometry:
Ethan Nicholas52cad152017-02-16 16:37:32 -05003411 this->writeWord(SpvExecutionModelGeometry, out);
3412 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003413 default:
John Stilesf57207b2021-02-02 17:50:34 -05003414 SK_ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003415 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003416 SpvId entryPoint = fFunctionMap[main];
3417 this->writeWord(entryPoint, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003418 this->writeString(main->name().fChars, main->name().fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003419 for (int var : interfaceVars) {
3420 this->writeWord(var, out);
3421 }
John Stiles270cec22021-02-17 12:59:36 -05003422 if (program.fConfig->fKind == ProgramKind::kGeometry) {
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003423 this->writeGeometryShaderExecutionMode(entryPoint, out);
3424 }
John Stiles270cec22021-02-17 12:59:36 -05003425 if (program.fConfig->fKind == ProgramKind::kFragment) {
Greg Daniel64773e62016-11-22 09:44:03 -05003426 this->writeInstruction(SpvOpExecutionMode,
3427 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003428 SpvExecutionModeOriginUpperLeft,
3429 out);
3430 }
Brian Osman133724c2020-10-28 14:14:39 -04003431 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003432 if (e->is<Extension>()) {
3433 this->writeInstruction(SpvOpSourceExtension, e->as<Extension>().name().c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003434 }
3435 }
Greg Daniel64773e62016-11-22 09:44:03 -05003436
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003437 write_stringstream(fExtraGlobalsBuffer, out);
3438 write_stringstream(fNameBuffer, out);
3439 write_stringstream(fDecorationBuffer, out);
3440 write_stringstream(fConstantBuffer, out);
3441 write_stringstream(fExternalFunctionsBuffer, out);
3442 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003443}
3444
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003445bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003446 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003447 this->writeWord(SpvMagicNumber, *fOut);
3448 this->writeWord(SpvVersion, *fOut);
3449 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003450 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003451 this->writeInstructions(fProgram, buffer);
3452 this->writeWord(fIdCount, *fOut);
3453 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003454 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003455 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003456}
3457
John Stilesa6841be2020-08-06 14:11:56 -04003458} // namespace SkSL