blob: 2833d7c8104c9e7c414bb830751848de6cb0c633 [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"
13#include "src/sksl/ir/SkSLExpressionStatement.h"
14#include "src/sksl/ir/SkSLExtension.h"
15#include "src/sksl/ir/SkSLIndexExpression.h"
16#include "src/sksl/ir/SkSLVariableReference.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070017
18namespace SkSL {
19
ethannicholasb3058bd2016-07-01 08:22:01 -070020static const int32_t SKSL_MAGIC = 0x0; // FIXME: we should probably register a magic number
21
22void SPIRVCodeGenerator::setupIntrinsics() {
23#define ALL_GLSL(x) std::make_tuple(kGLSL_STD_450_IntrinsicKind, GLSLstd450 ## x, GLSLstd450 ## x, \
24 GLSLstd450 ## x, GLSLstd450 ## x)
25#define BY_TYPE_GLSL(ifFloat, ifInt, ifUInt) std::make_tuple(kGLSL_STD_450_IntrinsicKind, \
26 GLSLstd450 ## ifFloat, \
27 GLSLstd450 ## ifInt, \
28 GLSLstd450 ## ifUInt, \
29 SpvOpUndef)
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040030#define ALL_SPIRV(x) std::make_tuple(kSPIRV_IntrinsicKind, SpvOp ## x, SpvOp ## x, SpvOp ## x, \
31 SpvOp ## x)
ethannicholasb3058bd2016-07-01 08:22:01 -070032#define SPECIAL(x) std::make_tuple(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic, \
33 k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
34 k ## x ## _SpecialIntrinsic)
Ethan Nicholas0df1b042017-03-31 13:56:23 -040035 fIntrinsicMap[String("round")] = ALL_GLSL(Round);
36 fIntrinsicMap[String("roundEven")] = ALL_GLSL(RoundEven);
37 fIntrinsicMap[String("trunc")] = ALL_GLSL(Trunc);
38 fIntrinsicMap[String("abs")] = BY_TYPE_GLSL(FAbs, SAbs, SAbs);
39 fIntrinsicMap[String("sign")] = BY_TYPE_GLSL(FSign, SSign, SSign);
40 fIntrinsicMap[String("floor")] = ALL_GLSL(Floor);
41 fIntrinsicMap[String("ceil")] = ALL_GLSL(Ceil);
42 fIntrinsicMap[String("fract")] = ALL_GLSL(Fract);
43 fIntrinsicMap[String("radians")] = ALL_GLSL(Radians);
44 fIntrinsicMap[String("degrees")] = ALL_GLSL(Degrees);
45 fIntrinsicMap[String("sin")] = ALL_GLSL(Sin);
46 fIntrinsicMap[String("cos")] = ALL_GLSL(Cos);
47 fIntrinsicMap[String("tan")] = ALL_GLSL(Tan);
48 fIntrinsicMap[String("asin")] = ALL_GLSL(Asin);
49 fIntrinsicMap[String("acos")] = ALL_GLSL(Acos);
50 fIntrinsicMap[String("atan")] = SPECIAL(Atan);
51 fIntrinsicMap[String("sinh")] = ALL_GLSL(Sinh);
52 fIntrinsicMap[String("cosh")] = ALL_GLSL(Cosh);
53 fIntrinsicMap[String("tanh")] = ALL_GLSL(Tanh);
54 fIntrinsicMap[String("asinh")] = ALL_GLSL(Asinh);
55 fIntrinsicMap[String("acosh")] = ALL_GLSL(Acosh);
56 fIntrinsicMap[String("atanh")] = ALL_GLSL(Atanh);
57 fIntrinsicMap[String("pow")] = ALL_GLSL(Pow);
58 fIntrinsicMap[String("exp")] = ALL_GLSL(Exp);
59 fIntrinsicMap[String("log")] = ALL_GLSL(Log);
60 fIntrinsicMap[String("exp2")] = ALL_GLSL(Exp2);
61 fIntrinsicMap[String("log2")] = ALL_GLSL(Log2);
62 fIntrinsicMap[String("sqrt")] = ALL_GLSL(Sqrt);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040063 fIntrinsicMap[String("inverse")] = ALL_GLSL(MatrixInverse);
64 fIntrinsicMap[String("transpose")] = ALL_SPIRV(Transpose);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040065 fIntrinsicMap[String("inversesqrt")] = ALL_GLSL(InverseSqrt);
66 fIntrinsicMap[String("determinant")] = ALL_GLSL(Determinant);
67 fIntrinsicMap[String("matrixInverse")] = ALL_GLSL(MatrixInverse);
Ethan Nicholas70a44b22017-11-30 09:09:16 -050068 fIntrinsicMap[String("mod")] = SPECIAL(Mod);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050069 fIntrinsicMap[String("min")] = SPECIAL(Min);
70 fIntrinsicMap[String("max")] = SPECIAL(Max);
71 fIntrinsicMap[String("clamp")] = SPECIAL(Clamp);
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040072 fIntrinsicMap[String("saturate")] = SPECIAL(Saturate);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040073 fIntrinsicMap[String("dot")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
Ethan Nicholas0187ae62017-05-03 11:03:44 -040074 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050075 fIntrinsicMap[String("mix")] = SPECIAL(Mix);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040076 fIntrinsicMap[String("step")] = ALL_GLSL(Step);
77 fIntrinsicMap[String("smoothstep")] = ALL_GLSL(SmoothStep);
78 fIntrinsicMap[String("fma")] = ALL_GLSL(Fma);
79 fIntrinsicMap[String("frexp")] = ALL_GLSL(Frexp);
80 fIntrinsicMap[String("ldexp")] = ALL_GLSL(Ldexp);
ethannicholasb3058bd2016-07-01 08:22:01 -070081
Ethan Nicholas0df1b042017-03-31 13:56:23 -040082#define PACK(type) fIntrinsicMap[String("pack" #type)] = ALL_GLSL(Pack ## type); \
83 fIntrinsicMap[String("unpack" #type)] = ALL_GLSL(Unpack ## type)
ethannicholasb3058bd2016-07-01 08:22:01 -070084 PACK(Snorm4x8);
85 PACK(Unorm4x8);
86 PACK(Snorm2x16);
87 PACK(Unorm2x16);
88 PACK(Half2x16);
89 PACK(Double2x32);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040090 fIntrinsicMap[String("length")] = ALL_GLSL(Length);
91 fIntrinsicMap[String("distance")] = ALL_GLSL(Distance);
92 fIntrinsicMap[String("cross")] = ALL_GLSL(Cross);
93 fIntrinsicMap[String("normalize")] = ALL_GLSL(Normalize);
94 fIntrinsicMap[String("faceForward")] = ALL_GLSL(FaceForward);
95 fIntrinsicMap[String("reflect")] = ALL_GLSL(Reflect);
96 fIntrinsicMap[String("refract")] = ALL_GLSL(Refract);
97 fIntrinsicMap[String("findLSB")] = ALL_GLSL(FindILsb);
98 fIntrinsicMap[String("findMSB")] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
99 fIntrinsicMap[String("dFdx")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400100 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700101 fIntrinsicMap[String("dFdy")] = SPECIAL(DFdy);
Chris Dalton09212192018-11-13 15:07:24 -0500102 fIntrinsicMap[String("fwidth")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFwidth,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400103 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400104 fIntrinsicMap[String("makeSampler2D")] = SPECIAL(SampledImage);
105
Ethan Nicholas13863662019-07-29 13:05:15 -0400106 fIntrinsicMap[String("sample")] = SPECIAL(Texture);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400107 fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
Greg Daniel64773e62016-11-22 09:44:03 -0500108
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400109 fIntrinsicMap[String("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400110 SpvOpUndef, SpvOpUndef, SpvOpAny);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400111 fIntrinsicMap[String("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400112 SpvOpUndef, SpvOpUndef, SpvOpAll);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400113 fIntrinsicMap[String("equal")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400114 SpvOpFOrdEqual, SpvOpIEqual,
115 SpvOpIEqual, SpvOpLogicalEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400116 fIntrinsicMap[String("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400117 SpvOpFOrdNotEqual, SpvOpINotEqual,
118 SpvOpINotEqual,
119 SpvOpLogicalNotEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400120 fIntrinsicMap[String("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500121 SpvOpFOrdLessThan, SpvOpSLessThan,
122 SpvOpULessThan, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400123 fIntrinsicMap[String("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500124 SpvOpFOrdLessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400125 SpvOpSLessThanEqual,
126 SpvOpULessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400127 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400128 fIntrinsicMap[String("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500129 SpvOpFOrdGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400130 SpvOpSGreaterThan,
131 SpvOpUGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400132 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400133 fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500134 SpvOpFOrdGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400135 SpvOpSGreaterThanEqual,
136 SpvOpUGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400137 SpvOpUndef);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400138 fIntrinsicMap[String("EmitVertex")] = ALL_SPIRV(EmitVertex);
139 fIntrinsicMap[String("EndPrimitive")] = ALL_SPIRV(EndPrimitive);
ethannicholasb3058bd2016-07-01 08:22:01 -0700140// interpolateAt* not yet supported...
141}
142
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400143void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700144 out.write((const char*) &word, sizeof(word));
ethannicholasb3058bd2016-07-01 08:22:01 -0700145}
146
ethannicholasd598f792016-07-25 10:08:54 -0700147static bool is_float(const Context& context, const Type& type) {
Ethan Nicholas0df21132018-07-10 09:37:51 -0400148 if (type.columns() > 1) {
ethannicholasd598f792016-07-25 10:08:54 -0700149 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700150 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400151 return type == *context.fFloat_Type || type == *context.fHalf_Type ||
152 type == *context.fDouble_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700153}
154
ethannicholasd598f792016-07-25 10:08:54 -0700155static bool is_signed(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700156 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700157 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700158 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400159 return type == *context.fInt_Type || type == *context.fShort_Type ||
160 type == *context.fByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700161}
162
ethannicholasd598f792016-07-25 10:08:54 -0700163static bool is_unsigned(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700164 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700165 return is_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700166 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400167 return type == *context.fUInt_Type || type == *context.fUShort_Type ||
168 type == *context.fUByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700169}
170
ethannicholasd598f792016-07-25 10:08:54 -0700171static bool is_bool(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700172 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700173 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700174 }
ethannicholasd598f792016-07-25 10:08:54 -0700175 return type == *context.fBool_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700176}
177
ethannicholasd598f792016-07-25 10:08:54 -0700178static bool is_out(const Variable& var) {
179 return (var.fModifiers.fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700180}
181
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400182void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400183 SkASSERT(opCode != SpvOpLoad || &out != &fConstantBuffer);
184 SkASSERT(opCode != SpvOpUndef);
ethannicholasb3058bd2016-07-01 08:22:01 -0700185 switch (opCode) {
186 case SpvOpReturn: // fall through
187 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700188 case SpvOpKill: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700189 case SpvOpBranch: // fall through
190 case SpvOpBranchConditional:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400191 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700192 fCurrentBlock = 0;
193 break;
194 case SpvOpConstant: // fall through
195 case SpvOpConstantTrue: // fall through
196 case SpvOpConstantFalse: // fall through
197 case SpvOpConstantComposite: // fall through
198 case SpvOpTypeVoid: // fall through
199 case SpvOpTypeInt: // fall through
200 case SpvOpTypeFloat: // fall through
201 case SpvOpTypeBool: // fall through
202 case SpvOpTypeVector: // fall through
203 case SpvOpTypeMatrix: // fall through
204 case SpvOpTypeArray: // fall through
205 case SpvOpTypePointer: // fall through
206 case SpvOpTypeFunction: // fall through
207 case SpvOpTypeRuntimeArray: // fall through
208 case SpvOpTypeStruct: // fall through
209 case SpvOpTypeImage: // fall through
210 case SpvOpTypeSampledImage: // fall through
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400211 case SpvOpTypeSampler: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700212 case SpvOpVariable: // fall through
213 case SpvOpFunction: // fall through
214 case SpvOpFunctionParameter: // fall through
215 case SpvOpFunctionEnd: // fall through
216 case SpvOpExecutionMode: // fall through
217 case SpvOpMemoryModel: // fall through
218 case SpvOpCapability: // fall through
219 case SpvOpExtInstImport: // fall through
220 case SpvOpEntryPoint: // fall through
221 case SpvOpSource: // fall through
222 case SpvOpSourceExtension: // fall through
223 case SpvOpName: // fall through
224 case SpvOpMemberName: // fall through
225 case SpvOpDecorate: // fall through
226 case SpvOpMemberDecorate:
227 break;
228 default:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400229 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700230 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700231 this->writeWord((length << 16) | opCode, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700232}
233
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400234void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700235 fCurrentBlock = label;
236 this->writeInstruction(SpvOpLabel, label, out);
237}
238
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400239void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700240 this->writeOpCode(opCode, 1, out);
241}
242
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400243void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700244 this->writeOpCode(opCode, 2, out);
245 this->writeWord(word1, out);
246}
247
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700248void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputStream& out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400249 out.write(string, length);
ethannicholasb3058bd2016-07-01 08:22:01 -0700250 switch (length % 4) {
251 case 1:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500252 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700253 // fall through
254 case 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500255 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700256 // fall through
257 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500258 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700259 break;
260 default:
261 this->writeWord(0, out);
262 }
263}
264
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700265void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out) {
266 this->writeOpCode(opCode, 1 + (string.fLength + 4) / 4, out);
267 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700268}
269
270
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700271void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400272 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700273 this->writeOpCode(opCode, 2 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700274 this->writeWord(word1, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700275 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700276}
277
Greg Daniel64773e62016-11-22 09:44:03 -0500278void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700279 StringFragment string, OutputStream& out) {
280 this->writeOpCode(opCode, 3 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700281 this->writeWord(word1, out);
282 this->writeWord(word2, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700283 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700284}
285
Greg Daniel64773e62016-11-22 09:44:03 -0500286void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400287 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700288 this->writeOpCode(opCode, 3, out);
289 this->writeWord(word1, out);
290 this->writeWord(word2, out);
291}
292
Greg Daniel64773e62016-11-22 09:44:03 -0500293void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400294 int32_t word3, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700295 this->writeOpCode(opCode, 4, out);
296 this->writeWord(word1, out);
297 this->writeWord(word2, out);
298 this->writeWord(word3, out);
299}
300
Greg Daniel64773e62016-11-22 09:44:03 -0500301void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400302 int32_t word3, int32_t word4, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700303 this->writeOpCode(opCode, 5, out);
304 this->writeWord(word1, out);
305 this->writeWord(word2, out);
306 this->writeWord(word3, out);
307 this->writeWord(word4, out);
308}
309
Greg Daniel64773e62016-11-22 09:44:03 -0500310void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
311 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400312 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700313 this->writeOpCode(opCode, 6, out);
314 this->writeWord(word1, out);
315 this->writeWord(word2, out);
316 this->writeWord(word3, out);
317 this->writeWord(word4, out);
318 this->writeWord(word5, out);
319}
320
Greg Daniel64773e62016-11-22 09:44:03 -0500321void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700322 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400323 int32_t word6, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700324 this->writeOpCode(opCode, 7, out);
325 this->writeWord(word1, out);
326 this->writeWord(word2, out);
327 this->writeWord(word3, out);
328 this->writeWord(word4, out);
329 this->writeWord(word5, out);
330 this->writeWord(word6, out);
331}
332
Greg Daniel64773e62016-11-22 09:44:03 -0500333void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700334 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400335 int32_t word6, int32_t word7, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700336 this->writeOpCode(opCode, 8, out);
337 this->writeWord(word1, out);
338 this->writeWord(word2, out);
339 this->writeWord(word3, out);
340 this->writeWord(word4, out);
341 this->writeWord(word5, out);
342 this->writeWord(word6, out);
343 this->writeWord(word7, out);
344}
345
Greg Daniel64773e62016-11-22 09:44:03 -0500346void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700347 int32_t word3, int32_t word4, int32_t word5,
348 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400349 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700350 this->writeOpCode(opCode, 9, out);
351 this->writeWord(word1, out);
352 this->writeWord(word2, out);
353 this->writeWord(word3, out);
354 this->writeWord(word4, out);
355 this->writeWord(word5, out);
356 this->writeWord(word6, out);
357 this->writeWord(word7, out);
358 this->writeWord(word8, out);
359}
360
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400361void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700362 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
363 if (fCapabilities & bit) {
364 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
365 }
366 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400367 if (fProgram.fKind == Program::kGeometry_Kind) {
368 this->writeInstruction(SpvOpCapability, SpvCapabilityGeometry, out);
369 }
Ethan Nicholas81d15112018-07-13 12:48:50 -0400370 else {
371 this->writeInstruction(SpvOpCapability, SpvCapabilityShader, out);
372 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700373}
374
375SpvId SPIRVCodeGenerator::nextId() {
376 return fIdCount++;
377}
378
Ethan Nicholas19671772016-11-28 16:30:17 -0500379void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
380 SpvId resultId) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700381 this->writeInstruction(SpvOpName, resultId, type.name().c_str(), fNameBuffer);
382 // go ahead and write all of the field types, so we don't inadvertently write them while we're
383 // in the middle of writing the struct instruction
384 std::vector<SpvId> types;
385 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500386 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700387 }
388 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
389 this->writeWord(resultId, fConstantBuffer);
390 for (SpvId id : types) {
391 this->writeWord(id, fConstantBuffer);
392 }
393 size_t offset = 0;
394 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400395 const Type::Field& field = type.fields()[i];
396 size_t size = memoryLayout.size(*field.fType);
397 size_t alignment = memoryLayout.alignment(*field.fType);
398 const Layout& fieldLayout = field.fModifiers.fLayout;
Ethan Nicholas19671772016-11-28 16:30:17 -0500399 if (fieldLayout.fOffset >= 0) {
Greg Danieldbd44c72017-01-24 15:12:12 -0500400 if (fieldLayout.fOffset < (int) offset) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700401 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400402 "offset of field '" + field.fName + "' must be at "
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500403 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -0500404 }
405 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700406 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400407 "offset of field '" + field.fName + "' must be a multiple"
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500408 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -0500409 }
410 offset = fieldLayout.fOffset;
411 } else {
412 size_t mod = offset % alignment;
413 if (mod) {
414 offset += alignment - mod;
415 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700416 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400417 this->writeInstruction(SpvOpMemberName, resultId, i, field.fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500418 this->writeLayout(fieldLayout, resultId, i);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400419 if (field.fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -0500420 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700421 (SpvId) offset, fDecorationBuffer);
422 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400423 if (field.fType->kind() == Type::kMatrix_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -0500424 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -0700425 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500426 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400427 (SpvId) memoryLayout.stride(*field.fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800428 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700429 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400430 if (!field.fType->highPrecision()) {
431 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i,
432 SpvDecorationRelaxedPrecision, fDecorationBuffer);
433 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700434 offset += size;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400435 Type::Kind kind = field.fType->kind();
ethannicholasb3058bd2016-07-01 08:22:01 -0700436 if ((kind == Type::kArray_Kind || kind == Type::kStruct_Kind) && offset % alignment != 0) {
437 offset += alignment - offset % alignment;
438 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700439 }
440}
441
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400442Type SPIRVCodeGenerator::getActualType(const Type& type) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500443 if (type.isFloat()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400444 return *fContext.fFloat_Type;
445 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500446 if (type.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400447 return *fContext.fInt_Type;
448 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500449 if (type.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400450 return *fContext.fUInt_Type;
451 }
452 if (type.kind() == Type::kMatrix_Kind || type.kind() == Type::kVector_Kind) {
453 if (type.componentType() == *fContext.fHalf_Type) {
454 return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
455 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400456 if (type.componentType() == *fContext.fShort_Type ||
457 type.componentType() == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400458 return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
459 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400460 if (type.componentType() == *fContext.fUShort_Type ||
461 type.componentType() == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400462 return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
463 }
464 }
465 return type;
466}
467
ethannicholasb3058bd2016-07-01 08:22:01 -0700468SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800469 return this->getType(type, fDefaultLayout);
470}
471
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400472SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
473 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400474 String key = type.name() + to_string((int) layout.fStd);
ethannicholas8ac838d2016-11-22 08:39:36 -0800475 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700476 if (entry == fTypeMap.end()) {
477 SpvId result = this->nextId();
478 switch (type.kind()) {
479 case Type::kScalar_Kind:
ethannicholasd598f792016-07-25 10:08:54 -0700480 if (type == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700481 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500482 } else if (type == *fContext.fInt_Type || type == *fContext.fShort_Type ||
483 type == *fContext.fIntLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700484 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500485 } else if (type == *fContext.fUInt_Type || type == *fContext.fUShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700486 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500487 } else if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type ||
488 type == *fContext.fFloatLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700489 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -0700490 } else if (type == *fContext.fDouble_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700491 this->writeInstruction(SpvOpTypeFloat, result, 64, fConstantBuffer);
492 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400493 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700494 }
495 break;
496 case Type::kVector_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500497 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800498 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700499 type.columns(), fConstantBuffer);
500 break;
501 case Type::kMatrix_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500502 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800503 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700504 type.columns(), fConstantBuffer);
505 break;
506 case Type::kStruct_Kind:
ethannicholas8ac838d2016-11-22 08:39:36 -0800507 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700508 break;
509 case Type::kArray_Kind: {
510 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700511 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500512 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800513 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700514 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500515 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400516 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800517 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700518 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400519 SkASSERT(false); // we shouldn't have any runtime-sized arrays right now
Greg Daniel64773e62016-11-22 09:44:03 -0500520 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800521 this->getType(type.componentType(), layout),
522 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400523 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
524 (int32_t) layout.stride(type),
525 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700526 }
527 break;
528 }
529 case Type::kSampler_Kind: {
Greg Daniel64773e62016-11-22 09:44:03 -0500530 SpvId image = result;
531 if (SpvDimSubpassData != type.dimensions()) {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400532 if (type.textureType()) {
533 image = this->getType(*type.textureType(), layout);
534 } else {
535 image = nextId();
536 }
Greg Daniel64773e62016-11-22 09:44:03 -0500537 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400538 if (SpvDimBuffer == type.dimensions()) {
539 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
540 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400541 if (!type.textureType()) {
542 this->writeInstruction(SpvOpTypeImage, image,
543 this->getType(*fContext.fFloat_Type, layout),
544 type.dimensions(), type.isDepth(), type.isArrayed(),
545 type.isMultisampled(), type.isSampled() ? 1 : 2,
546 SpvImageFormatUnknown, fConstantBuffer);
547 fImageTypeMap[key] = image;
548 }
Greg Daniel64773e62016-11-22 09:44:03 -0500549 if (SpvDimSubpassData != type.dimensions()) {
550 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
551 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700552 break;
553 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400554 case Type::kSeparateSampler_Kind: {
555 this->writeInstruction(SpvOpTypeSampler, result, fConstantBuffer);
556 break;
557 }
558 case Type::kTexture_Kind: {
559 // FIXME: should support more than 2D
560 this->writeInstruction(SpvOpTypeImage, result,
561 this->getType(*fContext.fFloat_Type, layout),
562 SpvDim2D, type.isDepth(), type.isArrayed(),
563 type.isMultisampled(), 1,
564 SpvImageFormatUnknown, fConstantBuffer);
565 fImageTypeMap[key] = result;
566 break;
567 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700568 default:
ethannicholasd598f792016-07-25 10:08:54 -0700569 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700570 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
571 } else {
572 ABORT("invalid type: %s", type.description().c_str());
573 }
574 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800575 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700576 return result;
577 }
578 return entry->second;
579}
580
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400581SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400582 SkASSERT(type.kind() == Type::kSampler_Kind);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400583 this->getType(type);
584 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400585 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400586 return fImageTypeMap[key];
587}
588
ethannicholasd598f792016-07-25 10:08:54 -0700589SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400590 String key = function.fReturnType.description() + "(";
591 String separator;
ethannicholasd598f792016-07-25 10:08:54 -0700592 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700593 key += separator;
594 separator = ", ";
ethannicholasd598f792016-07-25 10:08:54 -0700595 key += function.fParameters[i]->fType.description();
ethannicholasb3058bd2016-07-01 08:22:01 -0700596 }
597 key += ")";
598 auto entry = fTypeMap.find(key);
599 if (entry == fTypeMap.end()) {
600 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -0700601 int32_t length = 3 + (int32_t) function.fParameters.size();
602 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700603 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -0700604 for (size_t i = 0; i < function.fParameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500605 // glslang seems to treat all function arguments as pointers whether they need to be or
606 // not. I was initially puzzled by this until I ran bizarre failures with certain
607 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700608 // failure case:
609 //
610 // void sphere(float x) {
611 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500612 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700613 // void map() {
614 // sphere(1.0);
615 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500616 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700617 // void main() {
618 // for (int i = 0; i < 1; i++) {
619 // map();
620 // }
621 // }
622 //
Greg Daniel64773e62016-11-22 09:44:03 -0500623 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
624 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700625 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
626 // the spec makes this make sense.
627// if (is_out(function->fParameters[i])) {
ethannicholasd598f792016-07-25 10:08:54 -0700628 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -0700629 SpvStorageClassFunction));
630// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700631// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700632// }
633 }
634 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
635 this->writeWord(result, fConstantBuffer);
636 this->writeWord(returnType, fConstantBuffer);
637 for (SpvId id : parameterTypes) {
638 this->writeWord(id, fConstantBuffer);
639 }
640 fTypeMap[key] = result;
641 return result;
642 }
643 return entry->second;
644}
645
ethannicholas8ac838d2016-11-22 08:39:36 -0800646SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
647 return this->getPointerType(type, fDefaultLayout, storageClass);
648}
649
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400650SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700651 SpvStorageClass_ storageClass) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400652 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400653 String key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700654 auto entry = fTypeMap.find(key);
655 if (entry == fTypeMap.end()) {
656 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500657 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700658 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700659 fTypeMap[key] = result;
660 return result;
661 }
662 return entry->second;
663}
664
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400665SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700666 switch (expr.fKind) {
667 case Expression::kBinary_Kind:
668 return this->writeBinaryExpression((BinaryExpression&) expr, out);
669 case Expression::kBoolLiteral_Kind:
670 return this->writeBoolLiteral((BoolLiteral&) expr);
671 case Expression::kConstructor_Kind:
672 return this->writeConstructor((Constructor&) expr, out);
673 case Expression::kIntLiteral_Kind:
674 return this->writeIntLiteral((IntLiteral&) expr);
675 case Expression::kFieldAccess_Kind:
676 return this->writeFieldAccess(((FieldAccess&) expr), out);
677 case Expression::kFloatLiteral_Kind:
678 return this->writeFloatLiteral(((FloatLiteral&) expr));
679 case Expression::kFunctionCall_Kind:
680 return this->writeFunctionCall((FunctionCall&) expr, out);
681 case Expression::kPrefix_Kind:
682 return this->writePrefixExpression((PrefixExpression&) expr, out);
683 case Expression::kPostfix_Kind:
684 return this->writePostfixExpression((PostfixExpression&) expr, out);
685 case Expression::kSwizzle_Kind:
686 return this->writeSwizzle((Swizzle&) expr, out);
687 case Expression::kVariableReference_Kind:
688 return this->writeVariableReference((VariableReference&) expr, out);
689 case Expression::kTernary_Kind:
690 return this->writeTernaryExpression((TernaryExpression&) expr, out);
691 case Expression::kIndex_Kind:
692 return this->writeIndexExpression((IndexExpression&) expr, out);
693 default:
694 ABORT("unsupported expression: %s", expr.description().c_str());
695 }
696 return -1;
697}
698
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400699SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700700 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400701 SkASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -0700702 int32_t intrinsicId;
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400703 if (c.fArguments.size() > 0) {
704 const Type& type = c.fArguments[0]->fType;
705 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
706 intrinsicId = std::get<1>(intrinsic->second);
707 } else if (is_signed(fContext, type)) {
708 intrinsicId = std::get<2>(intrinsic->second);
709 } else if (is_unsigned(fContext, type)) {
710 intrinsicId = std::get<3>(intrinsic->second);
711 } else if (is_bool(fContext, type)) {
712 intrinsicId = std::get<4>(intrinsic->second);
713 } else {
714 intrinsicId = std::get<1>(intrinsic->second);
715 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700716 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400717 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700718 }
719 switch (std::get<0>(intrinsic->second)) {
720 case kGLSL_STD_450_IntrinsicKind: {
721 SpvId result = this->nextId();
722 std::vector<SpvId> arguments;
723 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400724 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
725 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
726 } else {
727 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
728 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700729 }
730 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700731 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700732 this->writeWord(result, out);
733 this->writeWord(fGLSLExtendedInstructions, out);
734 this->writeWord(intrinsicId, out);
735 for (SpvId id : arguments) {
736 this->writeWord(id, out);
737 }
738 return result;
739 }
740 case kSPIRV_IntrinsicKind: {
741 SpvId result = this->nextId();
742 std::vector<SpvId> arguments;
743 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400744 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
745 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
746 } else {
747 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
748 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700749 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400750 if (c.fType != *fContext.fVoid_Type) {
751 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
752 this->writeWord(this->getType(c.fType), out);
753 this->writeWord(result, out);
754 } else {
755 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
756 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700757 for (SpvId id : arguments) {
758 this->writeWord(id, out);
759 }
760 return result;
761 }
762 case kSpecial_IntrinsicKind:
763 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
764 default:
765 ABORT("unsupported intrinsic kind");
766 }
767}
768
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500769std::vector<SpvId> SPIRVCodeGenerator::vectorize(
770 const std::vector<std::unique_ptr<Expression>>& args,
771 OutputStream& out) {
772 int vectorSize = 0;
773 for (const auto& a : args) {
774 if (a->fType.kind() == Type::kVector_Kind) {
775 if (vectorSize) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400776 SkASSERT(a->fType.columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500777 }
778 else {
779 vectorSize = a->fType.columns();
780 }
781 }
782 }
783 std::vector<SpvId> result;
784 for (const auto& a : args) {
785 SpvId raw = this->writeExpression(*a, out);
786 if (vectorSize && a->fType.kind() == Type::kScalar_Kind) {
787 SpvId vector = this->nextId();
788 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
789 this->writeWord(this->getType(a->fType.toCompound(fContext, vectorSize, 1)), out);
790 this->writeWord(vector, out);
791 for (int i = 0; i < vectorSize; i++) {
792 this->writeWord(raw, out);
793 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400794 this->writePrecisionModifier(a->fType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500795 result.push_back(vector);
796 } else {
797 result.push_back(raw);
798 }
799 }
800 return result;
801}
802
803void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
804 SpvId signedInst, SpvId unsignedInst,
805 const std::vector<SpvId>& args,
806 OutputStream& out) {
807 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
808 this->writeWord(this->getType(type), out);
809 this->writeWord(id, out);
810 this->writeWord(fGLSLExtendedInstructions, out);
811
812 if (is_float(fContext, type)) {
813 this->writeWord(floatInst, out);
814 } else if (is_signed(fContext, type)) {
815 this->writeWord(signedInst, out);
816 } else if (is_unsigned(fContext, type)) {
817 this->writeWord(unsignedInst, out);
818 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400819 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500820 }
821 for (SpvId a : args) {
822 this->writeWord(a, out);
823 }
824}
825
Greg Daniel64773e62016-11-22 09:44:03 -0500826SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400827 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700828 SpvId result = this->nextId();
829 switch (kind) {
830 case kAtan_SpecialIntrinsic: {
831 std::vector<SpvId> arguments;
832 for (size_t i = 0; i < c.fArguments.size(); i++) {
833 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
834 }
835 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700836 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700837 this->writeWord(result, out);
838 this->writeWord(fGLSLExtendedInstructions, out);
839 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
840 for (SpvId id : arguments) {
841 this->writeWord(id, out);
842 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400843 break;
844 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400845 case kSampledImage_SpecialIntrinsic: {
846 SkASSERT(2 == c.fArguments.size());
847 SpvId img = this->writeExpression(*c.fArguments[0], out);
848 SpvId sampler = this->writeExpression(*c.fArguments[1], out);
849 this->writeInstruction(SpvOpSampledImage,
850 this->getType(c.fType),
851 result,
852 img,
853 sampler,
854 out);
855 break;
856 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400857 case kSubpassLoad_SpecialIntrinsic: {
858 SpvId img = this->writeExpression(*c.fArguments[0], out);
859 std::vector<std::unique_ptr<Expression>> args;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700860 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
861 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
862 Constructor ctor(-1, *fContext.fFloat2_Type, std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400863 SpvId coords = this->writeConstantVector(ctor);
864 if (1 == c.fArguments.size()) {
865 this->writeInstruction(SpvOpImageRead,
866 this->getType(c.fType),
867 result,
868 img,
869 coords,
870 out);
871 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400872 SkASSERT(2 == c.fArguments.size());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400873 SpvId sample = this->writeExpression(*c.fArguments[1], out);
874 this->writeInstruction(SpvOpImageRead,
875 this->getType(c.fType),
876 result,
877 img,
878 coords,
879 SpvImageOperandsSampleMask,
880 sample,
881 out);
882 }
883 break;
884 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700885 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500886 SpvOp_ op = SpvOpImageSampleImplicitLod;
887 switch (c.fArguments[0]->fType.dimensions()) {
888 case SpvDim1D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400889 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500890 op = SpvOpImageSampleProjImplicitLod;
891 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400892 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500893 }
894 break;
895 case SpvDim2D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400896 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500897 op = SpvOpImageSampleProjImplicitLod;
898 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400899 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500900 }
901 break;
902 case SpvDim3D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400903 if (c.fArguments[1]->fType == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500904 op = SpvOpImageSampleProjImplicitLod;
905 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400906 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500907 }
908 break;
909 case SpvDimCube: // fall through
910 case SpvDimRect: // fall through
911 case SpvDimBuffer: // fall through
912 case SpvDimSubpassData:
913 break;
914 }
ethannicholasd598f792016-07-25 10:08:54 -0700915 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700916 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
917 SpvId uv = this->writeExpression(*c.fArguments[1], out);
918 if (c.fArguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500919 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700920 SpvImageOperandsBiasMask,
921 this->writeExpression(*c.fArguments[2], out),
922 out);
923 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400924 SkASSERT(c.fArguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500925 if (fProgram.fSettings.fSharpenTextures) {
926 FloatLiteral lodBias(fContext, -1, -0.5);
927 this->writeInstruction(op, type, result, sampler, uv,
928 SpvImageOperandsBiasMask,
929 this->writeFloatLiteral(lodBias),
930 out);
931 } else {
932 this->writeInstruction(op, type, result, sampler, uv,
933 out);
934 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700935 }
936 break;
937 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500938 case kMod_SpecialIntrinsic: {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500939 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400940 SkASSERT(args.size() == 2);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500941 const Type& operandType = c.fArguments[0]->fType;
942 SpvOp_ op;
943 if (is_float(fContext, operandType)) {
944 op = SpvOpFMod;
945 } else if (is_signed(fContext, operandType)) {
946 op = SpvOpSMod;
947 } else if (is_unsigned(fContext, operandType)) {
948 op = SpvOpUMod;
949 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400950 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500951 return 0;
952 }
953 this->writeOpCode(op, 5, out);
954 this->writeWord(this->getType(operandType), out);
955 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500956 this->writeWord(args[0], out);
957 this->writeWord(args[1], out);
958 break;
959 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700960 case kDFdy_SpecialIntrinsic: {
961 SpvId fn = this->writeExpression(*c.fArguments[0], out);
962 this->writeOpCode(SpvOpDPdy, 4, out);
963 this->writeWord(this->getType(c.fType), out);
964 this->writeWord(result, out);
965 this->writeWord(fn, out);
966 if (fProgram.fSettings.fFlipY) {
967 // Flipping Y also negates the Y derivatives.
968 SpvId flipped = this->nextId();
969 this->writeInstruction(SpvOpFNegate, this->getType(c.fType), flipped, result, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -0400970 this->writePrecisionModifier(c.fType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700971 return flipped;
972 }
973 break;
974 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500975 case kClamp_SpecialIntrinsic: {
976 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400977 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500978 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
979 GLSLstd450UClamp, args, out);
980 break;
981 }
982 case kMax_SpecialIntrinsic: {
983 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400984 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500985 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMax, GLSLstd450SMax,
986 GLSLstd450UMax, args, out);
987 break;
988 }
989 case kMin_SpecialIntrinsic: {
990 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400991 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500992 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMin, GLSLstd450SMin,
993 GLSLstd450UMin, args, out);
994 break;
995 }
996 case kMix_SpecialIntrinsic: {
997 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400998 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500999 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMix, SpvOpUndef,
1000 SpvOpUndef, args, out);
1001 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -05001002 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001003 case kSaturate_SpecialIntrinsic: {
1004 SkASSERT(c.fArguments.size() == 1);
1005 std::vector<std::unique_ptr<Expression>> finalArgs;
1006 finalArgs.push_back(c.fArguments[0]->clone());
1007 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 0));
1008 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 1));
1009 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
1010 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
1011 GLSLstd450UClamp, spvArgs, out);
1012 break;
1013 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001014 }
1015 return result;
1016}
1017
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001018SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001019 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07001020 if (entry == fFunctionMap.end()) {
1021 return this->writeIntrinsicCall(c, out);
1022 }
1023 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001024 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
ethannicholasb3058bd2016-07-01 08:22:01 -07001025 std::vector<SpvId> arguments;
1026 for (size_t i = 0; i < c.fArguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001027 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001028 // passed directly
1029 SpvId tmpVar;
1030 // if we need a temporary var to store this argument, this is the value to store in the var
1031 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -07001032 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001033 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
1034 SpvId ptr = lv->getPointer();
1035 if (ptr) {
1036 arguments.push_back(ptr);
1037 continue;
1038 } else {
1039 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1040 // copy it into a temp, call the function, read the value out of the temp, and then
1041 // update the lvalue.
1042 tmpValueId = lv->load(out);
1043 tmpVar = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001044 lvalues.push_back(std::make_tuple(tmpVar, &c.fArguments[i]->fType, std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001045 }
1046 } else {
1047 // see getFunctionType for an explanation of why we're always using pointer parameters
1048 tmpValueId = this->writeExpression(*c.fArguments[i], out);
1049 tmpVar = this->nextId();
1050 }
Greg Daniel64773e62016-11-22 09:44:03 -05001051 this->writeInstruction(SpvOpVariable,
1052 this->getPointerType(c.fArguments[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -07001053 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001054 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001055 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001056 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001057 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1058 arguments.push_back(tmpVar);
1059 }
1060 SpvId result = this->nextId();
1061 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001062 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001063 this->writeWord(result, out);
1064 this->writeWord(entry->second, out);
1065 for (SpvId id : arguments) {
1066 this->writeWord(id, out);
1067 }
1068 // now that the call is complete, we may need to update some lvalues with the new values of out
1069 // arguments
1070 for (const auto& tuple : lvalues) {
1071 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001072 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1073 out);
1074 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001075 std::get<2>(tuple)->store(load, out);
1076 }
1077 return result;
1078}
1079
ethannicholasf789b382016-08-03 12:43:36 -07001080SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001081 SkASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001082 SpvId result = this->nextId();
1083 std::vector<SpvId> arguments;
1084 for (size_t i = 0; i < c.fArguments.size(); i++) {
1085 arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1086 }
ethannicholasd598f792016-07-25 10:08:54 -07001087 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001088 if (c.fArguments.size() == 1) {
1089 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001090 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001091 this->writeWord(type, fConstantBuffer);
1092 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001093 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001094 this->writeWord(arguments[0], fConstantBuffer);
1095 }
1096 } else {
Greg Daniel64773e62016-11-22 09:44:03 -05001097 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001098 fConstantBuffer);
1099 this->writeWord(type, fConstantBuffer);
1100 this->writeWord(result, fConstantBuffer);
1101 for (SpvId id : arguments) {
1102 this->writeWord(id, fConstantBuffer);
1103 }
1104 }
1105 return result;
1106}
1107
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001108SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001109 SkASSERT(c.fType.isFloat());
1110 SkASSERT(c.fArguments.size() == 1);
1111 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001112 SpvId result = this->nextId();
1113 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001114 if (c.fArguments[0]->fType.isSigned()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001115 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001116 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001117 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001118 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Greg Daniel64773e62016-11-22 09:44:03 -05001119 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001120 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001121 }
1122 return result;
1123}
1124
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001125SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001126 SkASSERT(c.fType.isSigned());
1127 SkASSERT(c.fArguments.size() == 1);
1128 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001129 SpvId result = this->nextId();
1130 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001131 if (c.fArguments[0]->fType.isFloat()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001132 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001133 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001134 }
1135 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001136 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001137 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001138 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001139 }
1140 return result;
1141}
1142
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001143SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001144 SkASSERT(c.fType.isUnsigned());
1145 SkASSERT(c.fArguments.size() == 1);
1146 SkASSERT(c.fArguments[0]->fType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001147 SpvId result = this->nextId();
1148 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001149 if (c.fArguments[0]->fType.isFloat()) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001150 this->writeInstruction(SpvOpConvertFToU, this->getType(c.fType), result, parameter,
1151 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001152 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001153 SkASSERT(c.fArguments[0]->fType.isSigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001154 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
1155 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001156 }
1157 return result;
1158}
1159
Ethan Nicholas84645e32017-02-09 13:57:14 -05001160void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001161 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001162 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001163 SpvId zeroId = this->writeFloatLiteral(zero);
1164 std::vector<SpvId> columnIds;
1165 for (int column = 0; column < type.columns(); column++) {
1166 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1167 out);
1168 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1169 out);
1170 SpvId columnId = this->nextId();
1171 this->writeWord(columnId, out);
1172 columnIds.push_back(columnId);
1173 for (int row = 0; row < type.columns(); row++) {
1174 this->writeWord(row == column ? diagonal : zeroId, out);
1175 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001176 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001177 }
1178 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1179 out);
1180 this->writeWord(this->getType(type), out);
1181 this->writeWord(id, out);
1182 for (SpvId id : columnIds) {
1183 this->writeWord(id, out);
1184 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001185 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001186}
1187
1188void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001189 const Type& dstType, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001190 SkASSERT(srcType.kind() == Type::kMatrix_Kind);
1191 SkASSERT(dstType.kind() == Type::kMatrix_Kind);
1192 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001193 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1194 srcType.rows(),
1195 1));
1196 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1197 dstType.rows(),
1198 1));
1199 SpvId zeroId;
1200 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001201 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001202 zeroId = this->writeFloatLiteral(zero);
1203 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001204 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001205 zeroId = this->writeIntLiteral(zero);
1206 } else {
1207 ABORT("unsupported matrix component type");
1208 }
1209 SpvId zeroColumn = 0;
1210 SpvId columns[4];
1211 for (int i = 0; i < dstType.columns(); i++) {
1212 if (i < srcType.columns()) {
1213 // we're still inside the src matrix, copy the column
1214 SpvId srcColumn = this->nextId();
1215 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001216 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001217 SpvId dstColumn;
1218 if (srcType.rows() == dstType.rows()) {
1219 // columns are equal size, don't need to do anything
1220 dstColumn = srcColumn;
1221 }
1222 else if (dstType.rows() > srcType.rows()) {
1223 // dst column is bigger, need to zero-pad it
1224 dstColumn = this->nextId();
1225 int delta = dstType.rows() - srcType.rows();
1226 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1227 this->writeWord(dstColumnType, out);
1228 this->writeWord(dstColumn, out);
1229 this->writeWord(srcColumn, out);
1230 for (int i = 0; i < delta; ++i) {
1231 this->writeWord(zeroId, out);
1232 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001233 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001234 }
1235 else {
1236 // dst column is smaller, need to swizzle the src column
1237 dstColumn = this->nextId();
1238 int count = dstType.rows();
1239 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1240 this->writeWord(dstColumnType, out);
1241 this->writeWord(dstColumn, out);
1242 this->writeWord(srcColumn, out);
1243 this->writeWord(srcColumn, out);
1244 for (int i = 0; i < count; i++) {
1245 this->writeWord(i, out);
1246 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001247 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001248 }
1249 columns[i] = dstColumn;
1250 } else {
1251 // we're past the end of the src matrix, need a vector of zeroes
1252 if (!zeroColumn) {
1253 zeroColumn = this->nextId();
1254 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1255 this->writeWord(dstColumnType, out);
1256 this->writeWord(zeroColumn, out);
1257 for (int i = 0; i < dstType.rows(); ++i) {
1258 this->writeWord(zeroId, out);
1259 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001260 this->writePrecisionModifier(dstType, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001261 }
1262 columns[i] = zeroColumn;
1263 }
1264 }
1265 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1266 this->writeWord(this->getType(dstType), out);
1267 this->writeWord(id, out);
1268 for (int i = 0; i < dstType.columns(); i++) {
1269 this->writeWord(columns[i], out);
1270 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001271 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001272}
1273
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001274void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1275 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001276 std::vector<SpvId>* columnIds,
1277 int* currentCount, int rows, SpvId entry,
1278 OutputStream& out) {
1279 SkASSERT(*currentCount < rows);
1280 ++(*currentCount);
1281 currentColumn->push_back(entry);
1282 if (*currentCount == rows) {
1283 *currentCount = 0;
1284 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1285 this->writeWord(columnType, out);
1286 SpvId columnId = this->nextId();
1287 this->writeWord(columnId, out);
1288 columnIds->push_back(columnId);
1289 for (SpvId id : *currentColumn) {
1290 this->writeWord(id, out);
1291 }
1292 currentColumn->clear();
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001293 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001294 }
1295}
1296
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001297SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001298 SkASSERT(c.fType.kind() == Type::kMatrix_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001299 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1300 // an instruction
1301 std::vector<SpvId> arguments;
1302 for (size_t i = 0; i < c.fArguments.size(); i++) {
1303 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1304 }
1305 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001306 int rows = c.fType.rows();
1307 int columns = c.fType.columns();
Ethan Nicholas84645e32017-02-09 13:57:14 -05001308 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1309 this->writeUniformScaleMatrix(result, arguments[0], c.fType, out);
1310 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kMatrix_Kind) {
1311 this->writeMatrixCopy(result, arguments[0], c.fArguments[0]->fType, c.fType, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001312 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kVector_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001313 SkASSERT(c.fType.rows() == 2 && c.fType.columns() == 2);
1314 SkASSERT(c.fArguments[0]->fType.columns() == 4);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001315 SpvId componentType = this->getType(c.fType.componentType());
1316 SpvId v[4];
1317 for (int i = 0; i < 4; ++i) {
1318 v[i] = this->nextId();
1319 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i, out);
1320 }
1321 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, 2, 1));
1322 SpvId column1 = this->nextId();
1323 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1324 SpvId column2 = this->nextId();
1325 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
1326 this->writeInstruction(SpvOpCompositeConstruct, this->getType(c.fType), result, column1,
1327 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001328 } else {
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001329 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001330 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001331 // ids of vectors and scalars we have written to the current column so far
1332 std::vector<SpvId> currentColumn;
1333 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001334 int currentCount = 0;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001335 Precision precision = c.fType.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001336 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001337 if (currentCount == 0 && c.fArguments[i]->fType.kind() == Type::kVector_Kind &&
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001338 c.fArguments[i]->fType.columns() == c.fType.rows()) {
1339 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001340 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001341 } else {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001342 if (c.fArguments[i]->fType.columns() == 1) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001343 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1344 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001345 } else {
1346 SpvId componentType = this->getType(c.fArguments[i]->fType.componentType());
Ethan Nicholas811b9442018-05-11 13:16:03 -04001347 for (int j = 0; j < c.fArguments[i]->fType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001348 SpvId swizzle = this->nextId();
1349 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1350 arguments[i], j, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001351 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1352 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001353 }
1354 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001355 }
1356 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001357 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001358 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001359 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001360 this->writeWord(result, out);
1361 for (SpvId id : columnIds) {
1362 this->writeWord(id, out);
1363 }
1364 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001365 this->writePrecisionModifier(c.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001366 return result;
1367}
1368
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001369SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001370 SkASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001371 if (c.isConstant()) {
1372 return this->writeConstantVector(c);
1373 }
1374 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1375 // an instruction
1376 std::vector<SpvId> arguments;
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001377 for (size_t i = 0; i < c.fArguments.size(); i++) {
1378 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
1379 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1380 // extract the components and convert them in that case manually. On top of that,
1381 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1382 // doesn't handle vector arguments at all, so we always extract vector components and
1383 // pass them into OpCreateComposite individually.
1384 SpvId vec = this->writeExpression(*c.fArguments[i], out);
1385 SpvOp_ op = SpvOpUndef;
1386 const Type& src = c.fArguments[i]->fType.componentType();
1387 const Type& dst = c.fType.componentType();
1388 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1389 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1390 if (c.fArguments.size() == 1) {
1391 return vec;
1392 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001393 } else if (src == *fContext.fInt_Type ||
1394 src == *fContext.fShort_Type ||
1395 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001396 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001397 } else if (src == *fContext.fUInt_Type ||
1398 src == *fContext.fUShort_Type ||
1399 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001400 op = SpvOpConvertUToF;
1401 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001402 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001403 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001404 } else if (dst == *fContext.fInt_Type ||
1405 dst == *fContext.fShort_Type ||
1406 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001407 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1408 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001409 } else if (src == *fContext.fInt_Type ||
1410 src == *fContext.fShort_Type ||
1411 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001412 if (c.fArguments.size() == 1) {
1413 return vec;
1414 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001415 } else if (src == *fContext.fUInt_Type ||
1416 src == *fContext.fUShort_Type ||
1417 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001418 op = SpvOpBitcast;
1419 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001420 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001421 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001422 } else if (dst == *fContext.fUInt_Type ||
1423 dst == *fContext.fUShort_Type ||
1424 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001425 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1426 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001427 } else if (src == *fContext.fInt_Type ||
1428 src == *fContext.fShort_Type ||
1429 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001430 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001431 } else if (src == *fContext.fUInt_Type ||
1432 src == *fContext.fUShort_Type ||
1433 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001434 if (c.fArguments.size() == 1) {
1435 return vec;
1436 }
1437 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001438 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001439 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001440 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001441 for (int j = 0; j < c.fArguments[i]->fType.columns(); j++) {
1442 SpvId swizzle = this->nextId();
1443 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1444 out);
1445 if (op != SpvOpUndef) {
1446 SpvId cast = this->nextId();
1447 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1448 arguments.push_back(cast);
1449 } else {
1450 arguments.push_back(swizzle);
1451 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001452 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001453 } else {
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001454 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1455 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001456 }
1457 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001458 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1459 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1460 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001461 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001462 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001463 this->writeWord(arguments[0], out);
1464 }
1465 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001466 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001467 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001468 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001469 this->writeWord(result, out);
1470 for (SpvId id : arguments) {
1471 this->writeWord(id, out);
1472 }
1473 }
1474 return result;
1475}
1476
Ethan Nicholasbd553222017-07-18 15:54:59 -04001477SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001478 SkASSERT(c.fType.kind() == Type::kArray_Kind);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001479 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1480 // an instruction
1481 std::vector<SpvId> arguments;
1482 for (size_t i = 0; i < c.fArguments.size(); i++) {
1483 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1484 }
1485 SpvId result = this->nextId();
1486 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
1487 this->writeWord(this->getType(c.fType), out);
1488 this->writeWord(result, out);
1489 for (SpvId id : arguments) {
1490 this->writeWord(id, out);
1491 }
1492 return result;
1493}
1494
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001495SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001496 if (c.fArguments.size() == 1 &&
1497 this->getActualType(c.fType) == this->getActualType(c.fArguments[0]->fType)) {
1498 return this->writeExpression(*c.fArguments[0], out);
1499 }
1500 if (c.fType == *fContext.fFloat_Type || c.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001501 return this->writeFloatConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001502 } else if (c.fType == *fContext.fInt_Type ||
1503 c.fType == *fContext.fShort_Type ||
1504 c.fType == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001505 return this->writeIntConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001506 } else if (c.fType == *fContext.fUInt_Type ||
1507 c.fType == *fContext.fUShort_Type ||
1508 c.fType == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001509 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001510 }
ethannicholasd598f792016-07-25 10:08:54 -07001511 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001512 case Type::kVector_Kind:
1513 return this->writeVectorConstructor(c, out);
1514 case Type::kMatrix_Kind:
1515 return this->writeMatrixConstructor(c, out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001516 case Type::kArray_Kind:
1517 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001518 default:
1519 ABORT("unsupported constructor: %s", c.description().c_str());
1520 }
1521}
1522
1523SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1524 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001525 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001526 return SpvStorageClassInput;
1527 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001528 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001529 return SpvStorageClassOutput;
1530 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001531 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001532 return SpvStorageClassPushConstant;
1533 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001534 return SpvStorageClassUniform;
1535 } else {
1536 return SpvStorageClassFunction;
1537 }
1538}
1539
ethannicholasf789b382016-08-03 12:43:36 -07001540SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001541 switch (expr.fKind) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001542 case Expression::kVariableReference_Kind: {
1543 const Variable& var = ((VariableReference&) expr).fVariable;
1544 if (var.fStorage != Variable::kGlobal_Storage) {
1545 return SpvStorageClassFunction;
1546 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001547 SpvStorageClass_ result = get_storage_class(var.fModifiers);
1548 if (result == SpvStorageClassFunction) {
1549 result = SpvStorageClassPrivate;
1550 }
1551 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001552 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001553 case Expression::kFieldAccess_Kind:
1554 return get_storage_class(*((FieldAccess&) expr).fBase);
1555 case Expression::kIndex_Kind:
1556 return get_storage_class(*((IndexExpression&) expr).fBase);
1557 default:
1558 return SpvStorageClassFunction;
1559 }
1560}
1561
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001562std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001563 std::vector<SpvId> chain;
1564 switch (expr.fKind) {
1565 case Expression::kIndex_Kind: {
1566 IndexExpression& indexExpr = (IndexExpression&) expr;
1567 chain = this->getAccessChain(*indexExpr.fBase, out);
1568 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1569 break;
1570 }
1571 case Expression::kFieldAccess_Kind: {
1572 FieldAccess& fieldExpr = (FieldAccess&) expr;
1573 chain = this->getAccessChain(*fieldExpr.fBase, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001574 IntLiteral index(fContext, -1, fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001575 chain.push_back(this->writeIntLiteral(index));
1576 break;
1577 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001578 default: {
1579 SpvId id = this->getLValue(expr, out)->getPointer();
1580 SkASSERT(id != 0);
1581 chain.push_back(id);
1582 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001583 }
1584 return chain;
1585}
1586
1587class PointerLValue : public SPIRVCodeGenerator::LValue {
1588public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001589 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1590 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001591 : fGen(gen)
1592 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001593 , fType(type)
1594 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001595
1596 virtual SpvId getPointer() override {
1597 return fPointer;
1598 }
1599
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001600 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001601 SpvId result = fGen.nextId();
1602 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001603 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001604 return result;
1605 }
1606
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001607 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001608 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1609 }
1610
1611private:
1612 SPIRVCodeGenerator& fGen;
1613 const SpvId fPointer;
1614 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001615 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001616};
1617
1618class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1619public:
Greg Daniel64773e62016-11-22 09:44:03 -05001620 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001621 const Type& baseType, const Type& swizzleType,
1622 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001623 : fGen(gen)
1624 , fVecPointer(vecPointer)
1625 , fComponents(components)
1626 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001627 , fSwizzleType(swizzleType)
1628 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001629
1630 virtual SpvId getPointer() override {
1631 return 0;
1632 }
1633
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001634 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001635 SpvId base = fGen.nextId();
1636 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001637 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001638 SpvId result = fGen.nextId();
1639 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1640 fGen.writeWord(fGen.getType(fSwizzleType), out);
1641 fGen.writeWord(result, out);
1642 fGen.writeWord(base, out);
1643 fGen.writeWord(base, out);
1644 for (int component : fComponents) {
1645 fGen.writeWord(component, out);
1646 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001647 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001648 return result;
1649 }
1650
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001651 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001652 // use OpVectorShuffle to mix and match the vector components. We effectively create
1653 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001654 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001655 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001656 // float3L = ...;
1657 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001658 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001659 // 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 -07001660 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1661 // (3, 1, 4).
1662 SpvId base = fGen.nextId();
1663 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1664 SpvId shuffle = fGen.nextId();
1665 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1666 fGen.writeWord(fGen.getType(fBaseType), out);
1667 fGen.writeWord(shuffle, out);
1668 fGen.writeWord(base, out);
1669 fGen.writeWord(value, out);
1670 for (int i = 0; i < fBaseType.columns(); i++) {
1671 // current offset into the virtual vector, defaults to pulling the unmodified
1672 // value from the left side
1673 int offset = i;
1674 // check to see if we are writing this component
1675 for (size_t j = 0; j < fComponents.size(); j++) {
1676 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001677 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001678 // the correct component of the right side instead of preserving the
1679 // value from the left
1680 offset = (int) (j + fBaseType.columns());
1681 break;
1682 }
1683 }
1684 fGen.writeWord(offset, out);
1685 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001686 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001687 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1688 }
1689
1690private:
1691 SPIRVCodeGenerator& fGen;
1692 const SpvId fVecPointer;
1693 const std::vector<int>& fComponents;
1694 const Type& fBaseType;
1695 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001696 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001697};
1698
Greg Daniel64773e62016-11-22 09:44:03 -05001699std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001700 OutputStream& out) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001701 Precision precision = expr.fType.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001702 switch (expr.fKind) {
1703 case Expression::kVariableReference_Kind: {
Ethan Nicholas5226b772018-05-03 16:20:41 -04001704 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07001705 const Variable& var = ((VariableReference&) expr).fVariable;
Ethan Nicholas5226b772018-05-03 16:20:41 -04001706 if (var.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
1707 type = this->getType(Type("sk_in", Type::kArray_Kind, var.fType.componentType(),
1708 fSkInCount));
1709 } else {
1710 type = this->getType(expr.fType);
1711 }
ethannicholasd598f792016-07-25 10:08:54 -07001712 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001713 SkASSERT(entry != fVariableMap.end());
Ethan Nicholas5226b772018-05-03 16:20:41 -04001714 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(*this,
1715 entry->second,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001716 type,
1717 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001718 }
1719 case Expression::kIndex_Kind: // fall through
1720 case Expression::kFieldAccess_Kind: {
1721 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1722 SpvId member = this->nextId();
1723 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001724 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001725 this->writeWord(member, out);
1726 for (SpvId idx : chain) {
1727 this->writeWord(idx, out);
1728 }
1729 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -04001730 *this,
1731 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001732 this->getType(expr.fType),
1733 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001734 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001735 case Expression::kSwizzle_Kind: {
1736 Swizzle& swizzle = (Swizzle&) expr;
1737 size_t count = swizzle.fComponents.size();
1738 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001739 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001740 if (count == 1) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001741 IntLiteral index(fContext, -1, swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001742 SpvId member = this->nextId();
1743 this->writeInstruction(SpvOpAccessChain,
Greg Daniel64773e62016-11-22 09:44:03 -05001744 this->getPointerType(swizzle.fType,
1745 get_storage_class(*swizzle.fBase)),
1746 member,
1747 base,
1748 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001749 out);
1750 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1751 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001752 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001753 this->getType(expr.fType),
1754 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001755 } else {
1756 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
Greg Daniel64773e62016-11-22 09:44:03 -05001757 *this,
1758 base,
1759 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001760 swizzle.fBase->fType,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001761 expr.fType,
1762 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001763 }
1764 }
Ethan Nicholasa583b812018-01-18 13:32:11 -05001765 case Expression::kTernary_Kind: {
1766 TernaryExpression& t = (TernaryExpression&) expr;
1767 SpvId test = this->writeExpression(*t.fTest, out);
1768 SpvId end = this->nextId();
1769 SpvId ifTrueLabel = this->nextId();
1770 SpvId ifFalseLabel = this->nextId();
1771 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1772 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1773 this->writeLabel(ifTrueLabel, out);
1774 SpvId ifTrue = this->getLValue(*t.fIfTrue, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001775 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001776 this->writeInstruction(SpvOpBranch, end, out);
1777 ifTrueLabel = fCurrentBlock;
1778 SpvId ifFalse = this->getLValue(*t.fIfFalse, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001779 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001780 ifFalseLabel = fCurrentBlock;
1781 this->writeInstruction(SpvOpBranch, end, out);
1782 SpvId result = this->nextId();
1783 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1784 ifTrueLabel, ifFalse, ifFalseLabel, out);
1785 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1786 *this,
1787 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001788 this->getType(expr.fType),
1789 precision));
Ethan Nicholasa583b812018-01-18 13:32:11 -05001790 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001791 default:
1792 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001793 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001794 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1795 // caught by IRGenerator
1796 SpvId result = this->nextId();
1797 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001798 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1799 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001800 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1801 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1802 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001803 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001804 this->getType(expr.fType),
1805 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001806 }
1807}
1808
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001809SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001810 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001811 auto entry = fVariableMap.find(&ref.fVariable);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001812 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001813 SpvId var = entry->second;
ethannicholasd598f792016-07-25 10:08:54 -07001814 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001815 this->writePrecisionModifier(ref.fVariable.fType, result);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001816 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
1817 fProgram.fSettings.fFlipY) {
1818 // need to remap to a top-left coordinate system
Greg Daniele6ab9982018-08-22 13:56:32 +00001819 if (fRTHeightStructId == (SpvId) -1) {
1820 // height variable hasn't been written yet
1821 std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors));
1822 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
1823 std::vector<Type::Field> fields;
1824 fields.emplace_back(Modifiers(), SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1825 StringFragment name("sksl_synthetic_uniforms");
1826 Type intfStruct(-1, name, fields);
1827 Layout layout(0, -1, -1, 1, -1, -1, -1, -1, Layout::Format::kUnspecified,
1828 Layout::kUnspecified_Primitive, -1, -1, "", Layout::kNo_Key,
Ethan Nicholas78aceb22018-08-31 16:13:58 -04001829 Layout::CType::kDefault);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001830 Variable* intfVar = (Variable*) fSynthetics.takeOwnership(std::unique_ptr<Symbol>(
1831 new Variable(-1,
1832 Modifiers(layout, Modifiers::kUniform_Flag),
1833 name,
1834 intfStruct,
1835 Variable::kGlobal_Storage)));
Greg Daniele6ab9982018-08-22 13:56:32 +00001836 InterfaceBlock intf(-1, intfVar, name, String(""),
1837 std::vector<std::unique_ptr<Expression>>(), st);
1838 fRTHeightStructId = this->writeInterfaceBlock(intf);
1839 fRTHeightFieldIndex = 0;
1840 }
1841 SkASSERT(fRTHeightFieldIndex != (SpvId) -1);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001842 // write float4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, gl_FragCoord.w)
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001843 SpvId xId = this->nextId();
1844 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1845 result, 0, out);
Greg Daniele6ab9982018-08-22 13:56:32 +00001846 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1847 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1848 SpvId heightPtr = this->nextId();
1849 this->writeOpCode(SpvOpAccessChain, 5, out);
1850 this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out);
1851 this->writeWord(heightPtr, out);
1852 this->writeWord(fRTHeightStructId, out);
1853 this->writeWord(fieldIndexId, out);
1854 SpvId heightRead = this->nextId();
1855 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1856 heightPtr, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001857 SpvId rawYId = this->nextId();
1858 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1859 result, 1, out);
1860 SpvId flippedYId = this->nextId();
1861 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
Greg Daniele6ab9982018-08-22 13:56:32 +00001862 heightRead, rawYId, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001863 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001864 SpvId zeroId = writeFloatLiteral(zero);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001865 FloatLiteral one(fContext, -1, 1.0);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001866 SpvId wId = this->nextId();
1867 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), wId,
1868 result, 3, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001869 SpvId flipped = this->nextId();
1870 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001871 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001872 this->writeWord(flipped, out);
1873 this->writeWord(xId, out);
1874 this->writeWord(flippedYId, out);
1875 this->writeWord(zeroId, out);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001876 this->writeWord(wId, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001877 return flipped;
1878 }
Chris Daltonb91c4662018-08-01 10:46:22 -06001879 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
1880 !fProgram.fSettings.fFlipY) {
1881 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1882 // the default convention of "counter-clockwise face is front".
1883 SpvId inverse = this->nextId();
1884 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1885 result, out);
1886 return inverse;
1887 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001888 return result;
1889}
1890
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001891SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001892 if (expr.fBase->fType.kind() == Type::Kind::kVector_Kind) {
1893 SpvId base = this->writeExpression(*expr.fBase, out);
1894 SpvId index = this->writeExpression(*expr.fIndex, out);
1895 SpvId result = this->nextId();
1896 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.fType), result, base,
1897 index, out);
1898 return result;
1899 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001900 return getLValue(expr, out)->load(out);
1901}
1902
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001903SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001904 return getLValue(f, out)->load(out);
1905}
1906
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001907SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001908 SpvId base = this->writeExpression(*swizzle.fBase, out);
1909 SpvId result = this->nextId();
1910 size_t count = swizzle.fComponents.size();
1911 if (count == 1) {
Greg Daniel64773e62016-11-22 09:44:03 -05001912 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
1913 swizzle.fComponents[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001914 } else {
1915 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
ethannicholasd598f792016-07-25 10:08:54 -07001916 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001917 this->writeWord(result, out);
1918 this->writeWord(base, out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001919 SpvId other;
1920 int last = swizzle.fComponents.back();
1921 if (last < 0) {
1922 if (!fConstantZeroOneVector) {
1923 FloatLiteral zero(fContext, -1, 0);
1924 SpvId zeroId = this->writeFloatLiteral(zero);
1925 FloatLiteral one(fContext, -1, 1);
Ethan Nicholas0b2c0542019-02-25 14:29:11 -05001926 SpvId oneId = this->writeFloatLiteral(one);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001927 SpvId type = this->getType(*fContext.fFloat2_Type);
1928 fConstantZeroOneVector = this->nextId();
1929 this->writeOpCode(SpvOpConstantComposite, 5, fConstantBuffer);
1930 this->writeWord(type, fConstantBuffer);
1931 this->writeWord(fConstantZeroOneVector, fConstantBuffer);
1932 this->writeWord(zeroId, fConstantBuffer);
1933 this->writeWord(oneId, fConstantBuffer);
1934 }
1935 other = fConstantZeroOneVector;
1936 } else {
1937 other = base;
1938 }
1939 this->writeWord(other, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001940 for (int component : swizzle.fComponents) {
Ethan Nicholasac285b12019-02-12 16:05:18 -05001941 if (component == SKSL_SWIZZLE_0) {
Ethan Nicholas0b2c0542019-02-25 14:29:11 -05001942 this->writeWord(swizzle.fBase->fType.columns(), out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001943 } else if (component == SKSL_SWIZZLE_1) {
Ethan Nicholas0b2c0542019-02-25 14:29:11 -05001944 this->writeWord(swizzle.fBase->fType.columns() + 1, out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001945 } else {
1946 this->writeWord(component, out);
1947 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001948 }
1949 }
1950 return result;
1951}
1952
Greg Daniel64773e62016-11-22 09:44:03 -05001953SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1954 const Type& operandType, SpvId lhs,
1955 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001956 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001957 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001958 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001959 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001960 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001961 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001962 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001963 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001964 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001965 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001966 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07001967 } else {
1968 ABORT("invalid operandType: %s", operandType.description().c_str());
1969 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04001970 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001971 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
1972 fDecorationBuffer);
1973 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001974 return result;
1975}
1976
Ethan Nicholas48e24052018-03-14 13:51:39 -04001977SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
1978 OutputStream& out) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05001979 if (operandType.kind() == Type::kVector_Kind) {
1980 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001981 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05001982 return result;
1983 }
1984 return id;
1985}
1986
Ethan Nicholas68990be2017-07-13 09:36:52 -04001987SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
1988 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04001989 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04001990 OutputStream& out) {
1991 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001992 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0df21132018-07-10 09:37:51 -04001993 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
1994 operandType.rows(),
1995 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04001996 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04001997 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04001998 1));
1999 SpvId boolType = this->getType(*fContext.fBool_Type);
2000 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04002001 for (int i = 0; i < operandType.columns(); i++) {
2002 SpvId columnL = this->nextId();
2003 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2004 SpvId columnR = this->nextId();
2005 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002006 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002007 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
2008 SpvId merge = this->nextId();
2009 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002010 if (result != 0) {
2011 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002012 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002013 result = next;
2014 }
2015 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002016 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04002017 }
2018 }
2019 return result;
2020}
2021
Ethan Nicholas0df21132018-07-10 09:37:51 -04002022SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
2023 SpvId rhs, SpvOp_ floatOperator,
2024 SpvOp_ intOperator,
2025 OutputStream& out) {
2026 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
2027 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
2028 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2029 operandType.rows(),
2030 1));
2031 SpvId columns[4];
2032 for (int i = 0; i < operandType.columns(); i++) {
2033 SpvId columnL = this->nextId();
2034 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2035 SpvId columnR = this->nextId();
2036 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2037 columns[i] = this->nextId();
2038 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2039 }
2040 SpvId result = this->nextId();
2041 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2042 this->writeWord(this->getType(operandType), out);
2043 this->writeWord(result, out);
2044 for (int i = 0; i < operandType.columns(); i++) {
2045 this->writeWord(columns[i], out);
2046 }
2047 return result;
2048}
2049
Ethan Nicholas49465b42019-04-17 12:22:21 -04002050std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2051 if (type.isInteger()) {
2052 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002053 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002054 else if (type.isFloat()) {
2055 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002056 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002057 ABORT("math is unsupported on type '%s'", type.name().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002058 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002059}
2060
2061SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Token::Kind op,
2062 const Type& rightType, SpvId rhs,
2063 const Type& resultType, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002064 Type tmp("<invalid>");
Ethan Nicholas48e24052018-03-14 13:51:39 -04002065 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002066 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002067 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2068 // handling in SPIR-V
Ethan Nicholas49465b42019-04-17 12:22:21 -04002069 if (this->getActualType(leftType) != this->getActualType(rightType)) {
2070 if (leftType.kind() == Type::kVector_Kind && rightType.isNumber()) {
2071 if (op == Token::SLASH) {
2072 SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
2073 SpvId inverse = this->nextId();
2074 this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
2075 rhs = inverse;
2076 op = Token::STAR;
2077 }
2078 if (op == Token::STAR) {
2079 SpvId result = this->nextId();
2080 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2081 result, lhs, rhs, out);
2082 return result;
2083 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002084 // promote number to vector
2085 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002086 const Type& vecType = leftType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002087 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2088 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002089 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002090 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002091 this->writeWord(rhs, out);
2092 }
2093 rhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002094 operandType = &leftType;
2095 } else if (rightType.kind() == Type::kVector_Kind && leftType.isNumber()) {
2096 if (op == Token::STAR) {
2097 SpvId result = this->nextId();
2098 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2099 result, rhs, lhs, out);
2100 return result;
2101 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002102 // promote number to vector
2103 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002104 const Type& vecType = rightType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002105 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2106 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002107 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002108 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002109 this->writeWord(lhs, out);
2110 }
2111 lhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002112 operandType = &rightType;
2113 } else if (leftType.kind() == Type::kMatrix_Kind) {
2114 SpvOp_ spvop;
2115 if (rightType.kind() == Type::kMatrix_Kind) {
2116 spvop = SpvOpMatrixTimesMatrix;
2117 } else if (rightType.kind() == Type::kVector_Kind) {
2118 spvop = SpvOpMatrixTimesVector;
ethannicholasb3058bd2016-07-01 08:22:01 -07002119 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002120 SkASSERT(rightType.kind() == Type::kScalar_Kind);
2121 spvop = SpvOpMatrixTimesScalar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002122 }
2123 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002124 this->writeInstruction(spvop, this->getType(resultType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002125 return result;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002126 } else if (rightType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002127 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002128 if (leftType.kind() == Type::kVector_Kind) {
2129 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(resultType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002130 lhs, rhs, out);
2131 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002132 SkASSERT(leftType.kind() == Type::kScalar_Kind);
2133 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(resultType), result,
2134 rhs, lhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002135 }
2136 return result;
2137 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002138 SkASSERT(false);
2139 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002140 }
2141 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002142 tmp = this->getActualType(leftType);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002143 operandType = &tmp;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002144 SkASSERT(*operandType == this->getActualType(rightType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002145 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002146 switch (op) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002147 case Token::EQEQ: {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002148 if (operandType->kind() == Type::kMatrix_Kind) {
2149 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002150 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002151 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002152 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002153 const Type* tmpType;
2154 if (operandType->kind() == Type::kVector_Kind) {
2155 tmpType = &fContext.fBool_Type->toCompound(fContext,
2156 operandType->columns(),
2157 operandType->rows());
2158 } else {
2159 tmpType = &resultType;
2160 }
2161 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002162 SpvOpFOrdEqual, SpvOpIEqual,
2163 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002164 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002165 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002166 case Token::NEQ:
Ethan Nicholas68990be2017-07-13 09:36:52 -04002167 if (operandType->kind() == Type::kMatrix_Kind) {
2168 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002169 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002170 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002171 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002172 const Type* tmpType;
2173 if (operandType->kind() == Type::kVector_Kind) {
2174 tmpType = &fContext.fBool_Type->toCompound(fContext,
2175 operandType->columns(),
2176 operandType->rows());
2177 } else {
2178 tmpType = &resultType;
2179 }
2180 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002181 SpvOpFOrdNotEqual, SpvOpINotEqual,
2182 SpvOpINotEqual, SpvOpLogicalNotEqual,
2183 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002184 *operandType, SpvOpAny, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002185 case Token::GT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002186 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002187 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2188 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002189 SpvOpUGreaterThan, SpvOpUndef, out);
2190 case Token::LT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002191 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002192 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002193 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
2194 case Token::GTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002195 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002196 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2197 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002198 SpvOpUGreaterThanEqual, SpvOpUndef, out);
2199 case Token::LTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002200 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002201 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2202 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002203 SpvOpULessThanEqual, SpvOpUndef, out);
2204 case Token::PLUS:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002205 if (leftType.kind() == Type::kMatrix_Kind &&
2206 rightType.kind() == Type::kMatrix_Kind) {
2207 SkASSERT(leftType == rightType);
2208 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002209 SpvOpFAdd, SpvOpIAdd, out);
2210 }
Greg Daniel64773e62016-11-22 09:44:03 -05002211 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002212 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2213 case Token::MINUS:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002214 if (leftType.kind() == Type::kMatrix_Kind &&
2215 rightType.kind() == Type::kMatrix_Kind) {
2216 SkASSERT(leftType == rightType);
2217 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002218 SpvOpFSub, SpvOpISub, out);
2219 }
Greg Daniel64773e62016-11-22 09:44:03 -05002220 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002221 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2222 case Token::STAR:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002223 if (leftType.kind() == Type::kMatrix_Kind &&
2224 rightType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002225 // matrix multiply
2226 SpvId result = this->nextId();
2227 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2228 lhs, rhs, out);
2229 return result;
2230 }
Greg Daniel64773e62016-11-22 09:44:03 -05002231 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002232 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2233 case Token::SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002234 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002235 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002236 case Token::PERCENT:
2237 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2238 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002239 case Token::SHL:
2240 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2241 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2242 SpvOpUndef, out);
2243 case Token::SHR:
2244 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2245 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2246 SpvOpUndef, out);
2247 case Token::BITWISEAND:
2248 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2249 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
2250 case Token::BITWISEOR:
2251 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2252 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
2253 case Token::BITWISEXOR:
2254 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2255 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002256 case Token::COMMA:
2257 return rhs;
ethannicholasb3058bd2016-07-01 08:22:01 -07002258 default:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002259 SkASSERT(false);
2260 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002261 }
2262}
2263
Ethan Nicholas49465b42019-04-17 12:22:21 -04002264SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
2265 // handle cases where we don't necessarily evaluate both LHS and RHS
2266 switch (b.fOperator) {
2267 case Token::EQ: {
2268 SpvId rhs = this->writeExpression(*b.fRight, out);
2269 this->getLValue(*b.fLeft, out)->store(rhs, out);
2270 return rhs;
2271 }
2272 case Token::LOGICALAND:
2273 return this->writeLogicalAnd(b, out);
2274 case Token::LOGICALOR:
2275 return this->writeLogicalOr(b, out);
2276 default:
2277 break;
2278 }
2279
2280 std::unique_ptr<LValue> lvalue;
2281 SpvId lhs;
2282 if (is_assignment(b.fOperator)) {
2283 lvalue = this->getLValue(*b.fLeft, out);
2284 lhs = lvalue->load(out);
2285 } else {
2286 lvalue = nullptr;
2287 lhs = this->writeExpression(*b.fLeft, out);
2288 }
2289 SpvId rhs = this->writeExpression(*b.fRight, out);
2290 SpvId result = this->writeBinaryExpression(b.fLeft->fType, lhs, remove_assignment(b.fOperator),
2291 b.fRight->fType, rhs, b.fType, out);
2292 if (lvalue) {
2293 lvalue->store(result, out);
2294 }
2295 return result;
2296}
2297
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002298SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002299 SkASSERT(a.fOperator == Token::LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002300 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002301 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2302 SpvId lhs = this->writeExpression(*a.fLeft, out);
2303 SpvId rhsLabel = this->nextId();
2304 SpvId end = this->nextId();
2305 SpvId lhsBlock = fCurrentBlock;
2306 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2307 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2308 this->writeLabel(rhsLabel, out);
2309 SpvId rhs = this->writeExpression(*a.fRight, out);
2310 SpvId rhsBlock = fCurrentBlock;
2311 this->writeInstruction(SpvOpBranch, end, out);
2312 this->writeLabel(end, out);
2313 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002314 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002315 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002316 return result;
2317}
2318
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002319SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002320 SkASSERT(o.fOperator == Token::LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002321 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002322 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2323 SpvId lhs = this->writeExpression(*o.fLeft, out);
2324 SpvId rhsLabel = this->nextId();
2325 SpvId end = this->nextId();
2326 SpvId lhsBlock = fCurrentBlock;
2327 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2328 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2329 this->writeLabel(rhsLabel, out);
2330 SpvId rhs = this->writeExpression(*o.fRight, out);
2331 SpvId rhsBlock = fCurrentBlock;
2332 this->writeInstruction(SpvOpBranch, end, out);
2333 this->writeLabel(end, out);
2334 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002335 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002336 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002337 return result;
2338}
2339
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002340SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002341 SpvId test = this->writeExpression(*t.fTest, out);
Ethan Nicholas0f21c232018-07-23 09:25:40 -04002342 if (t.fIfTrue->fType.columns() == 1 && t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002343 // both true and false are constants, can just use OpSelect
2344 SpvId result = this->nextId();
2345 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2346 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
Greg Daniel64773e62016-11-22 09:44:03 -05002347 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002348 out);
2349 return result;
2350 }
Greg Daniel64773e62016-11-22 09:44:03 -05002351 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002352 // Adreno. Switched to storing the result in a temp variable as glslang does.
2353 SpvId var = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002354 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002355 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002356 SpvId trueLabel = this->nextId();
2357 SpvId falseLabel = this->nextId();
2358 SpvId end = this->nextId();
2359 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2360 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2361 this->writeLabel(trueLabel, out);
2362 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2363 this->writeInstruction(SpvOpBranch, end, out);
2364 this->writeLabel(falseLabel, out);
2365 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2366 this->writeInstruction(SpvOpBranch, end, out);
2367 this->writeLabel(end, out);
2368 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002369 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002370 this->writePrecisionModifier(t.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002371 return result;
2372}
2373
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002374SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002375 if (p.fOperator == Token::MINUS) {
2376 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002377 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002378 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002379 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002380 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002381 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002382 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2383 } else {
2384 ABORT("unsupported prefix expression %s", p.description().c_str());
Brian Salomon23356442018-11-30 15:33:19 -05002385 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002386 this->writePrecisionModifier(p.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002387 return result;
2388 }
2389 switch (p.fOperator) {
2390 case Token::PLUS:
2391 return this->writeExpression(*p.fOperand, out);
2392 case Token::PLUSPLUS: {
2393 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002394 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002395 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2396 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002397 out);
2398 lv->store(result, out);
2399 return result;
2400 }
2401 case Token::MINUSMINUS: {
2402 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002403 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002404 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2405 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002406 out);
2407 lv->store(result, out);
2408 return result;
2409 }
ethannicholas5961bc92016-10-12 06:39:56 -07002410 case Token::LOGICALNOT: {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002411 SkASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002412 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002413 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002414 this->writeExpression(*p.fOperand, out), out);
2415 return result;
2416 }
ethannicholas5961bc92016-10-12 06:39:56 -07002417 case Token::BITWISENOT: {
2418 SpvId result = this->nextId();
2419 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2420 this->writeExpression(*p.fOperand, out), out);
2421 return result;
2422 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002423 default:
2424 ABORT("unsupported prefix expression: %s", p.description().c_str());
2425 }
2426}
2427
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002428SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002429 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2430 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002431 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002432 switch (p.fOperator) {
2433 case Token::PLUSPLUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002434 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002435 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2436 lv->store(temp, out);
2437 return result;
2438 }
2439 case Token::MINUSMINUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002440 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002441 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2442 lv->store(temp, out);
2443 return result;
2444 }
2445 default:
2446 ABORT("unsupported postfix expression %s", p.description().c_str());
2447 }
2448}
2449
ethannicholasf789b382016-08-03 12:43:36 -07002450SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002451 if (b.fValue) {
2452 if (fBoolTrue == 0) {
2453 fBoolTrue = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002454 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002455 fConstantBuffer);
2456 }
2457 return fBoolTrue;
2458 } else {
2459 if (fBoolFalse == 0) {
2460 fBoolFalse = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002461 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002462 fConstantBuffer);
2463 }
2464 return fBoolFalse;
2465 }
2466}
2467
ethannicholasf789b382016-08-03 12:43:36 -07002468SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002469 ConstantType type;
ethannicholasd598f792016-07-25 10:08:54 -07002470 if (i.fType == *fContext.fInt_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002471 type = ConstantType::kInt;
2472 } else if (i.fType == *fContext.fUInt_Type) {
2473 type = ConstantType::kUInt;
2474 } else if (i.fType == *fContext.fShort_Type) {
2475 type = ConstantType::kShort;
2476 } else if (i.fType == *fContext.fUShort_Type) {
2477 type = ConstantType::kUShort;
ethannicholasb3058bd2016-07-01 08:22:01 -07002478 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002479 std::pair<ConstantValue, ConstantType> key(i.fValue, type);
2480 auto entry = fNumberConstants.find(key);
2481 if (entry == fNumberConstants.end()) {
2482 SpvId result = this->nextId();
2483 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
2484 fConstantBuffer);
2485 fNumberConstants[key] = result;
2486 return result;
2487 }
2488 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002489}
2490
ethannicholasf789b382016-08-03 12:43:36 -07002491SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholase1f55022019-02-05 17:17:40 -05002492 if (f.fType != *fContext.fDouble_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002493 ConstantType type;
2494 if (f.fType == *fContext.fHalf_Type) {
2495 type = ConstantType::kHalf;
2496 } else {
2497 type = ConstantType::kFloat;
2498 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002499 float value = (float) f.fValue;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002500 std::pair<ConstantValue, ConstantType> key(f.fValue, type);
2501 auto entry = fNumberConstants.find(key);
2502 if (entry == fNumberConstants.end()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002503 SpvId result = this->nextId();
2504 uint32_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002505 SkASSERT(sizeof(bits) == sizeof(value));
ethannicholasb3058bd2016-07-01 08:22:01 -07002506 memcpy(&bits, &value, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002507 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
ethannicholasb3058bd2016-07-01 08:22:01 -07002508 fConstantBuffer);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002509 fNumberConstants[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002510 return result;
2511 }
2512 return entry->second;
2513 } else {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002514 std::pair<ConstantValue, ConstantType> key(f.fValue, ConstantType::kDouble);
2515 auto entry = fNumberConstants.find(key);
2516 if (entry == fNumberConstants.end()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002517 SpvId result = this->nextId();
2518 uint64_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002519 SkASSERT(sizeof(bits) == sizeof(f.fValue));
ethannicholasb3058bd2016-07-01 08:22:01 -07002520 memcpy(&bits, &f.fValue, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002521 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002522 bits & 0xffffffff, bits >> 32, fConstantBuffer);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002523 fNumberConstants[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002524 return result;
2525 }
2526 return entry->second;
2527 }
2528}
2529
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002530SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002531 SpvId result = fFunctionMap[&f];
Greg Daniel64773e62016-11-22 09:44:03 -05002532 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002533 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002534 this->writeInstruction(SpvOpName, result, f.fName, fNameBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002535 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002536 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002537 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002538 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002539 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002540 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2541 }
2542 return result;
2543}
2544
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002545SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2546 fVariableBuffer.reset();
ethannicholasb3058bd2016-07-01 08:22:01 -07002547 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2548 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002549 StringStream bodyBuffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04002550 this->writeBlock((Block&) *f.fBody, bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002551 write_stringstream(fVariableBuffer, out);
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002552 if (f.fDeclaration.fName == "main") {
2553 write_stringstream(fGlobalInitializersBuffer, out);
2554 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002555 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002556 if (fCurrentBlock) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002557 if (f.fDeclaration.fReturnType == *fContext.fVoid_Type) {
2558 this->writeInstruction(SpvOpReturn, out);
2559 } else {
2560 this->writeInstruction(SpvOpUnreachable, out);
2561 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002562 }
2563 this->writeInstruction(SpvOpFunctionEnd, out);
2564 return result;
2565}
2566
2567void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2568 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002569 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002570 fDecorationBuffer);
2571 }
2572 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002573 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002574 fDecorationBuffer);
2575 }
2576 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002577 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002578 fDecorationBuffer);
2579 }
2580 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002581 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002582 fDecorationBuffer);
2583 }
Greg Daniel64773e62016-11-22 09:44:03 -05002584 if (layout.fInputAttachmentIndex >= 0) {
2585 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2586 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002587 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002588 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002589 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002590 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002591 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002592 fDecorationBuffer);
2593 }
2594}
2595
2596void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2597 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002598 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002599 layout.fLocation, fDecorationBuffer);
2600 }
2601 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002602 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002603 layout.fBinding, fDecorationBuffer);
2604 }
2605 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002606 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002607 layout.fIndex, fDecorationBuffer);
2608 }
2609 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002610 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002611 layout.fSet, fDecorationBuffer);
2612 }
Greg Daniel64773e62016-11-22 09:44:03 -05002613 if (layout.fInputAttachmentIndex >= 0) {
2614 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2615 layout.fInputAttachmentIndex, fDecorationBuffer);
2616 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002617 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002618 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002619 layout.fBuiltin, fDecorationBuffer);
2620 }
2621}
2622
Ethan Nicholas81d15112018-07-13 12:48:50 -04002623static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2624 switch (m.fLayout.fPrimitive) {
2625 case Layout::kPoints_Primitive:
2626 *outSkInCount = 1;
2627 break;
2628 case Layout::kLines_Primitive:
2629 *outSkInCount = 2;
2630 break;
2631 case Layout::kLinesAdjacency_Primitive:
2632 *outSkInCount = 4;
2633 break;
2634 case Layout::kTriangles_Primitive:
2635 *outSkInCount = 3;
2636 break;
2637 case Layout::kTrianglesAdjacency_Primitive:
2638 *outSkInCount = 6;
2639 break;
2640 default:
2641 return;
2642 }
2643}
2644
ethannicholasf789b382016-08-03 12:43:36 -07002645SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas361941e2017-05-30 15:41:07 -04002646 bool isBuffer = (0 != (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag));
Ethan Nicholas39204fd2017-11-27 13:12:30 -05002647 bool pushConstant = (0 != (intf.fVariable.fModifiers.fLayout.fFlags &
2648 Layout::kPushConstant_Flag));
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002649 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2650 MemoryLayout(MemoryLayout::k430_Standard) :
2651 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002652 SpvId result = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002653 const Type* type = &intf.fVariable.fType;
Greg Daniele6ab9982018-08-22 13:56:32 +00002654 if (fProgram.fInputs.fRTHeight) {
2655 SkASSERT(fRTHeightStructId == (SpvId) -1);
2656 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002657 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002658 fRTHeightStructId = result;
2659 fRTHeightFieldIndex = fields.size();
2660 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002661 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002662 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002663 SpvId typeId;
2664 if (intf.fVariable.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2665 for (const auto& e : fProgram) {
2666 if (e.fKind == ProgramElement::kModifiers_Kind) {
2667 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholas81d15112018-07-13 12:48:50 -04002668 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002669 }
2670 }
2671 typeId = this->getType(Type("sk_in", Type::kArray_Kind, intf.fVariable.fType.componentType(),
2672 fSkInCount), memoryLayout);
2673 } else {
2674 typeId = this->getType(*type, memoryLayout);
2675 }
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002676 if (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag) {
2677 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002678 } else if (intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
2679 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002680 }
ethannicholasd598f792016-07-25 10:08:54 -07002681 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002682 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002683 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002684 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002685 Layout layout = intf.fVariable.fModifiers.fLayout;
2686 if (intf.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
2687 layout.fSet = 0;
2688 }
2689 this->writeLayout(layout, result);
ethannicholasd598f792016-07-25 10:08:54 -07002690 fVariableMap[&intf.fVariable] = result;
Greg Daniele6ab9982018-08-22 13:56:32 +00002691 if (fProgram.fInputs.fRTHeight) {
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002692 delete type;
2693 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002694 return result;
2695}
2696
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002697void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002698 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2699}
2700
2701void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2702 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002703 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2704 }
2705}
2706
ethannicholas5961bc92016-10-12 06:39:56 -07002707#define BUILTIN_IGNORE 9999
Greg Daniel64773e62016-11-22 09:44:03 -05002708void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002709 OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002710 for (size_t i = 0; i < decl.fVars.size(); i++) {
2711 if (decl.fVars[i]->fKind == Statement::kNop_Kind) {
2712 continue;
2713 }
2714 const VarDeclaration& varDecl = (VarDeclaration&) *decl.fVars[i];
2715 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002716 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2717 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002718 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002719 Modifiers::kWriteOnly_Flag |
2720 Modifiers::kCoherent_Flag |
2721 Modifiers::kVolatile_Flag |
2722 Modifiers::kRestrict_Flag)));
ethannicholas5961bc92016-10-12 06:39:56 -07002723 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2724 continue;
2725 }
2726 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2727 kind != Program::kFragment_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002728 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
ethannicholas5961bc92016-10-12 06:39:56 -07002729 continue;
2730 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05002731 if (!var->fReadCount && !var->fWriteCount &&
ethannicholas14fe8cc2016-09-07 13:37:16 -07002732 !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
2733 Modifiers::kOut_Flag |
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002734 Modifiers::kUniform_Flag |
2735 Modifiers::kBuffer_Flag))) {
ethannicholasd598f792016-07-25 10:08:54 -07002736 // variable is dead and not an input / output var (the Vulkan debug layers complain if
2737 // we elide an interface var, even if it's dead)
ethannicholasb3058bd2016-07-01 08:22:01 -07002738 continue;
2739 }
2740 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002741 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002742 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002743 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002744 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002745 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
Stephen Whiteff5d7a22019-07-26 17:42:06 -04002746 if (var->fType.kind() == Type::kSampler_Kind ||
2747 var->fType.kind() == Type::kSeparateSampler_Kind ||
2748 var->fType.kind() == Type::kTexture_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002749 storageClass = SpvStorageClassUniformConstant;
2750 } else {
2751 storageClass = SpvStorageClassUniform;
2752 }
2753 } else {
2754 storageClass = SpvStorageClassPrivate;
2755 }
2756 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002757 fVariableMap[var] = id;
Ethan Nicholas5226b772018-05-03 16:20:41 -04002758 SpvId type;
2759 if (var->fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2760 type = this->getPointerType(Type("sk_in", Type::kArray_Kind,
2761 var->fType.componentType(), fSkInCount),
2762 storageClass);
2763 } else {
2764 type = this->getPointerType(var->fType, storageClass);
2765 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002766 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002767 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002768 this->writePrecisionModifier(var->fType, id);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002769 if (varDecl.fValue) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002770 SkASSERT(!fCurrentBlock);
ethannicholasf789b382016-08-03 12:43:36 -07002771 fCurrentBlock = -1;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002772 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002773 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002774 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002775 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002776 this->writeLayout(var->fModifiers.fLayout, id);
Ethan Nicholas45b0f152017-07-24 14:36:40 -04002777 if (var->fModifiers.fFlags & Modifiers::kFlat_Flag) {
2778 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2779 }
2780 if (var->fModifiers.fFlags & Modifiers::kNoPerspective_Flag) {
2781 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2782 fDecorationBuffer);
2783 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002784 }
2785}
2786
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002787void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002788 for (const auto& stmt : decl.fVars) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002789 SkASSERT(stmt->fKind == Statement::kVarDeclaration_Kind);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002790 VarDeclaration& varDecl = (VarDeclaration&) *stmt;
2791 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002792 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2793 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002794 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002795 Modifiers::kWriteOnly_Flag |
2796 Modifiers::kCoherent_Flag |
2797 Modifiers::kVolatile_Flag |
2798 Modifiers::kRestrict_Flag)));
ethannicholasb3058bd2016-07-01 08:22:01 -07002799 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002800 fVariableMap[var] = id;
2801 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002802 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002803 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002804 if (varDecl.fValue) {
2805 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002806 this->writeInstruction(SpvOpStore, id, value, out);
2807 }
2808 }
2809}
2810
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002811void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002812 switch (s.fKind) {
Ethan Nicholascb670962017-04-20 19:31:52 -04002813 case Statement::kNop_Kind:
2814 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002815 case Statement::kBlock_Kind:
2816 this->writeBlock((Block&) s, out);
2817 break;
2818 case Statement::kExpression_Kind:
2819 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2820 break;
Greg Daniel64773e62016-11-22 09:44:03 -05002821 case Statement::kReturn_Kind:
ethannicholasb3058bd2016-07-01 08:22:01 -07002822 this->writeReturnStatement((ReturnStatement&) s, out);
2823 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002824 case Statement::kVarDeclarations_Kind:
2825 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002826 break;
2827 case Statement::kIf_Kind:
2828 this->writeIfStatement((IfStatement&) s, out);
2829 break;
2830 case Statement::kFor_Kind:
2831 this->writeForStatement((ForStatement&) s, out);
2832 break;
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002833 case Statement::kWhile_Kind:
2834 this->writeWhileStatement((WhileStatement&) s, out);
2835 break;
2836 case Statement::kDo_Kind:
2837 this->writeDoStatement((DoStatement&) s, out);
2838 break;
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002839 case Statement::kSwitch_Kind:
2840 this->writeSwitchStatement((SwitchStatement&) s, out);
2841 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002842 case Statement::kBreak_Kind:
2843 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2844 break;
2845 case Statement::kContinue_Kind:
2846 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2847 break;
2848 case Statement::kDiscard_Kind:
2849 this->writeInstruction(SpvOpKill, out);
2850 break;
2851 default:
2852 ABORT("unsupported statement: %s", s.description().c_str());
2853 }
2854}
2855
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002856void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002857 for (size_t i = 0; i < b.fStatements.size(); i++) {
2858 this->writeStatement(*b.fStatements[i], out);
2859 }
2860}
2861
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002862void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002863 SpvId test = this->writeExpression(*stmt.fTest, out);
2864 SpvId ifTrue = this->nextId();
2865 SpvId ifFalse = this->nextId();
2866 if (stmt.fIfFalse) {
2867 SpvId end = this->nextId();
2868 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2869 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2870 this->writeLabel(ifTrue, out);
2871 this->writeStatement(*stmt.fIfTrue, out);
2872 if (fCurrentBlock) {
2873 this->writeInstruction(SpvOpBranch, end, out);
2874 }
2875 this->writeLabel(ifFalse, out);
2876 this->writeStatement(*stmt.fIfFalse, out);
2877 if (fCurrentBlock) {
2878 this->writeInstruction(SpvOpBranch, end, out);
2879 }
2880 this->writeLabel(end, out);
2881 } else {
2882 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2883 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2884 this->writeLabel(ifTrue, out);
2885 this->writeStatement(*stmt.fIfTrue, out);
2886 if (fCurrentBlock) {
2887 this->writeInstruction(SpvOpBranch, ifFalse, out);
2888 }
2889 this->writeLabel(ifFalse, out);
2890 }
2891}
2892
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002893void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002894 if (f.fInitializer) {
2895 this->writeStatement(*f.fInitializer, out);
2896 }
2897 SpvId header = this->nextId();
2898 SpvId start = this->nextId();
2899 SpvId body = this->nextId();
2900 SpvId next = this->nextId();
2901 fContinueTarget.push(next);
2902 SpvId end = this->nextId();
2903 fBreakTarget.push(end);
2904 this->writeInstruction(SpvOpBranch, header, out);
2905 this->writeLabel(header, out);
2906 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002907 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002908 this->writeLabel(start, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002909 if (f.fTest) {
2910 SpvId test = this->writeExpression(*f.fTest, out);
2911 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2912 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002913 this->writeLabel(body, out);
2914 this->writeStatement(*f.fStatement, out);
2915 if (fCurrentBlock) {
2916 this->writeInstruction(SpvOpBranch, next, out);
2917 }
2918 this->writeLabel(next, out);
2919 if (f.fNext) {
2920 this->writeExpression(*f.fNext, out);
2921 }
2922 this->writeInstruction(SpvOpBranch, header, out);
2923 this->writeLabel(end, out);
2924 fBreakTarget.pop();
2925 fContinueTarget.pop();
2926}
2927
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002928void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002929 SpvId header = this->nextId();
2930 SpvId start = this->nextId();
2931 SpvId body = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04002932 SpvId continueTarget = this->nextId();
2933 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002934 SpvId end = this->nextId();
2935 fBreakTarget.push(end);
2936 this->writeInstruction(SpvOpBranch, header, out);
2937 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04002938 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002939 this->writeInstruction(SpvOpBranch, start, out);
2940 this->writeLabel(start, out);
2941 SpvId test = this->writeExpression(*w.fTest, out);
2942 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2943 this->writeLabel(body, out);
2944 this->writeStatement(*w.fStatement, out);
2945 if (fCurrentBlock) {
Ethan Nicholas0d997662019-04-08 09:46:01 -04002946 this->writeInstruction(SpvOpBranch, continueTarget, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002947 }
Ethan Nicholas0d997662019-04-08 09:46:01 -04002948 this->writeLabel(continueTarget, out);
2949 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002950 this->writeLabel(end, out);
2951 fBreakTarget.pop();
2952 fContinueTarget.pop();
2953}
2954
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002955void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002956 // We believe the do loop code below will work, but Skia doesn't actually use them and
2957 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2958 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2959 // message, simply remove the error call below to see whether our do loop support actually
2960 // works.
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002961 fErrors.error(d.fOffset, "internal error: do loop support has been disabled in SPIR-V, see "
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002962 "SkSLSPIRVCodeGenerator.cpp for details");
2963
2964 SpvId header = this->nextId();
2965 SpvId start = this->nextId();
2966 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04002967 SpvId continueTarget = this->nextId();
2968 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002969 SpvId end = this->nextId();
2970 fBreakTarget.push(end);
2971 this->writeInstruction(SpvOpBranch, header, out);
2972 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04002973 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002974 this->writeInstruction(SpvOpBranch, start, out);
2975 this->writeLabel(start, out);
2976 this->writeStatement(*d.fStatement, out);
2977 if (fCurrentBlock) {
2978 this->writeInstruction(SpvOpBranch, next, out);
2979 }
2980 this->writeLabel(next, out);
2981 SpvId test = this->writeExpression(*d.fTest, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04002982 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
2983 this->writeLabel(continueTarget, out);
2984 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002985 this->writeLabel(end, out);
2986 fBreakTarget.pop();
2987 fContinueTarget.pop();
2988}
2989
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002990void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
2991 SpvId value = this->writeExpression(*s.fValue, out);
2992 std::vector<SpvId> labels;
2993 SpvId end = this->nextId();
2994 SpvId defaultLabel = end;
2995 fBreakTarget.push(end);
2996 int size = 3;
2997 for (const auto& c : s.fCases) {
2998 SpvId label = this->nextId();
2999 labels.push_back(label);
3000 if (c->fValue) {
3001 size += 2;
3002 } else {
3003 defaultLabel = label;
3004 }
3005 }
3006 labels.push_back(end);
3007 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3008 this->writeOpCode(SpvOpSwitch, size, out);
3009 this->writeWord(value, out);
3010 this->writeWord(defaultLabel, out);
3011 for (size_t i = 0; i < s.fCases.size(); ++i) {
3012 if (!s.fCases[i]->fValue) {
3013 continue;
3014 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003015 SkASSERT(s.fCases[i]->fValue->fKind == Expression::kIntLiteral_Kind);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003016 this->writeWord(((IntLiteral&) *s.fCases[i]->fValue).fValue, out);
3017 this->writeWord(labels[i], out);
3018 }
3019 for (size_t i = 0; i < s.fCases.size(); ++i) {
3020 this->writeLabel(labels[i], out);
3021 for (const auto& stmt : s.fCases[i]->fStatements) {
3022 this->writeStatement(*stmt, out);
3023 }
3024 if (fCurrentBlock) {
3025 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3026 }
3027 }
3028 this->writeLabel(end, out);
3029 fBreakTarget.pop();
3030}
3031
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003032void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003033 if (r.fExpression) {
Greg Daniel64773e62016-11-22 09:44:03 -05003034 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003035 out);
3036 } else {
3037 this->writeInstruction(SpvOpReturn, out);
3038 }
3039}
3040
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003041void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003042 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003043 int invocations = 1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003044 for (const auto& e : fProgram) {
3045 if (e.fKind == ProgramElement::kModifiers_Kind) {
3046 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003047 if (m.fFlags & Modifiers::kIn_Flag) {
3048 if (m.fLayout.fInvocations != -1) {
3049 invocations = m.fLayout.fInvocations;
3050 }
3051 SpvId input;
3052 switch (m.fLayout.fPrimitive) {
3053 case Layout::kPoints_Primitive:
3054 input = SpvExecutionModeInputPoints;
3055 break;
3056 case Layout::kLines_Primitive:
3057 input = SpvExecutionModeInputLines;
3058 break;
3059 case Layout::kLinesAdjacency_Primitive:
3060 input = SpvExecutionModeInputLinesAdjacency;
3061 break;
3062 case Layout::kTriangles_Primitive:
3063 input = SpvExecutionModeTriangles;
3064 break;
3065 case Layout::kTrianglesAdjacency_Primitive:
3066 input = SpvExecutionModeInputTrianglesAdjacency;
3067 break;
3068 default:
3069 input = 0;
3070 break;
3071 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003072 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003073 if (input) {
3074 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3075 }
3076 } else if (m.fFlags & Modifiers::kOut_Flag) {
3077 SpvId output;
3078 switch (m.fLayout.fPrimitive) {
3079 case Layout::kPoints_Primitive:
3080 output = SpvExecutionModeOutputPoints;
3081 break;
3082 case Layout::kLineStrip_Primitive:
3083 output = SpvExecutionModeOutputLineStrip;
3084 break;
3085 case Layout::kTriangleStrip_Primitive:
3086 output = SpvExecutionModeOutputTriangleStrip;
3087 break;
3088 default:
3089 output = 0;
3090 break;
3091 }
3092 if (output) {
3093 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3094 }
3095 if (m.fLayout.fMaxVertices != -1) {
3096 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3097 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3098 out);
3099 }
3100 }
3101 }
3102 }
3103 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3104 invocations, out);
3105}
3106
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003107void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003108 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003109 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003110 std::set<SpvId> interfaceVars;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003111 // assign IDs to functions, determine sk_in size
3112 int skInSize = -1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003113 for (const auto& e : program) {
3114 switch (e.fKind) {
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003115 case ProgramElement::kFunction_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003116 FunctionDefinition& f = (FunctionDefinition&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003117 fFunctionMap[&f.fDeclaration] = this->nextId();
3118 break;
3119 }
3120 case ProgramElement::kModifiers_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003121 Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003122 if (m.fFlags & Modifiers::kIn_Flag) {
3123 switch (m.fLayout.fPrimitive) {
3124 case Layout::kPoints_Primitive: // break
3125 case Layout::kLines_Primitive:
3126 skInSize = 1;
3127 break;
3128 case Layout::kLinesAdjacency_Primitive: // break
3129 skInSize = 2;
3130 break;
3131 case Layout::kTriangles_Primitive: // break
3132 case Layout::kTrianglesAdjacency_Primitive:
3133 skInSize = 3;
3134 break;
3135 default:
3136 break;
3137 }
3138 }
3139 break;
3140 }
3141 default:
3142 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003143 }
3144 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003145 for (const auto& e : program) {
3146 if (e.fKind == ProgramElement::kInterfaceBlock_Kind) {
3147 InterfaceBlock& intf = (InterfaceBlock&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003148 if (SK_IN_BUILTIN == intf.fVariable.fModifiers.fLayout.fBuiltin) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003149 SkASSERT(skInSize != -1);
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003150 intf.fSizes.emplace_back(new IntLiteral(fContext, -1, skInSize));
3151 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003152 SpvId id = this->writeInterfaceBlock(intf);
Ethan Nicholas16c11962018-03-16 12:20:54 -04003153 if (((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
3154 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) &&
3155 intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003156 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003157 }
3158 }
3159 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003160 for (const auto& e : program) {
3161 if (e.fKind == ProgramElement::kVar_Kind) {
3162 this->writeGlobalVars(program.fKind, ((VarDeclarations&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003163 }
3164 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003165 for (const auto& e : program) {
3166 if (e.fKind == ProgramElement::kFunction_Kind) {
3167 this->writeFunction(((FunctionDefinition&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003168 }
3169 }
ethannicholasd598f792016-07-25 10:08:54 -07003170 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003171 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07003172 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003173 main = entry.first;
3174 }
3175 }
Ethan Nicholas1a668d22019-04-18 10:37:40 -04003176 if (!main) {
3177 fErrors.error(0, "program does not contain a main() function");
3178 return;
3179 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003180 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003181 const Variable* var = entry.first;
Greg Daniel64773e62016-11-22 09:44:03 -05003182 if (var->fStorage == Variable::kGlobal_Storage &&
Ethan Nicholas16c11962018-03-16 12:20:54 -04003183 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
Ethan Nicholasd23c8192018-09-26 17:01:24 -04003184 (var->fModifiers.fFlags & Modifiers::kOut_Flag))) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003185 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003186 }
3187 }
3188 this->writeCapabilities(out);
3189 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3190 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003191 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->fName.fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003192 (int32_t) interfaceVars.size(), out);
3193 switch (program.fKind) {
3194 case Program::kVertex_Kind:
3195 this->writeWord(SpvExecutionModelVertex, out);
3196 break;
3197 case Program::kFragment_Kind:
3198 this->writeWord(SpvExecutionModelFragment, out);
3199 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003200 case Program::kGeometry_Kind:
3201 this->writeWord(SpvExecutionModelGeometry, out);
3202 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003203 default:
3204 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003205 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003206 SpvId entryPoint = fFunctionMap[main];
3207 this->writeWord(entryPoint, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003208 this->writeString(main->fName.fChars, main->fName.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003209 for (int var : interfaceVars) {
3210 this->writeWord(var, out);
3211 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003212 if (program.fKind == Program::kGeometry_Kind) {
3213 this->writeGeometryShaderExecutionMode(entryPoint, out);
3214 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003215 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003216 this->writeInstruction(SpvOpExecutionMode,
3217 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003218 SpvExecutionModeOriginUpperLeft,
3219 out);
3220 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003221 for (const auto& e : program) {
3222 if (e.fKind == ProgramElement::kExtension_Kind) {
3223 this->writeInstruction(SpvOpSourceExtension, ((Extension&) e).fName.c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003224 }
3225 }
Greg Daniel64773e62016-11-22 09:44:03 -05003226
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003227 write_stringstream(fExtraGlobalsBuffer, out);
3228 write_stringstream(fNameBuffer, out);
3229 write_stringstream(fDecorationBuffer, out);
3230 write_stringstream(fConstantBuffer, out);
3231 write_stringstream(fExternalFunctionsBuffer, out);
3232 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003233}
3234
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003235bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003236 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003237 this->writeWord(SpvMagicNumber, *fOut);
3238 this->writeWord(SpvVersion, *fOut);
3239 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003240 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003241 this->writeInstructions(fProgram, buffer);
3242 this->writeWord(fIdCount, *fOut);
3243 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003244 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003245 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003246}
3247
3248}