blob: e2071c707c8794986c9f0fe8dadd7bed1379fe10 [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 White792e2302019-08-09 13:33:51 -0400532 image = this->getType(type.textureType(), layout);
Greg Daniel64773e62016-11-22 09:44:03 -0500533 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400534 if (SpvDimBuffer == type.dimensions()) {
535 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
536 }
Greg Daniel64773e62016-11-22 09:44:03 -0500537 if (SpvDimSubpassData != type.dimensions()) {
538 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
539 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700540 break;
541 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400542 case Type::kSeparateSampler_Kind: {
543 this->writeInstruction(SpvOpTypeSampler, result, fConstantBuffer);
544 break;
545 }
546 case Type::kTexture_Kind: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400547 this->writeInstruction(SpvOpTypeImage, result,
548 this->getType(*fContext.fFloat_Type, layout),
Stephen White792e2302019-08-09 13:33:51 -0400549 type.dimensions(), type.isDepth(), type.isArrayed(),
550 type.isMultisampled(), type.isSampled() ? 1 : 2,
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400551 SpvImageFormatUnknown, fConstantBuffer);
552 fImageTypeMap[key] = result;
553 break;
554 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700555 default:
ethannicholasd598f792016-07-25 10:08:54 -0700556 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700557 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
558 } else {
559 ABORT("invalid type: %s", type.description().c_str());
560 }
561 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800562 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700563 return result;
564 }
565 return entry->second;
566}
567
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400568SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400569 SkASSERT(type.kind() == Type::kSampler_Kind);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400570 this->getType(type);
571 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400572 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400573 return fImageTypeMap[key];
574}
575
ethannicholasd598f792016-07-25 10:08:54 -0700576SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400577 String key = function.fReturnType.description() + "(";
578 String separator;
ethannicholasd598f792016-07-25 10:08:54 -0700579 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700580 key += separator;
581 separator = ", ";
ethannicholasd598f792016-07-25 10:08:54 -0700582 key += function.fParameters[i]->fType.description();
ethannicholasb3058bd2016-07-01 08:22:01 -0700583 }
584 key += ")";
585 auto entry = fTypeMap.find(key);
586 if (entry == fTypeMap.end()) {
587 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -0700588 int32_t length = 3 + (int32_t) function.fParameters.size();
589 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700590 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -0700591 for (size_t i = 0; i < function.fParameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500592 // glslang seems to treat all function arguments as pointers whether they need to be or
593 // not. I was initially puzzled by this until I ran bizarre failures with certain
594 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700595 // failure case:
596 //
597 // void sphere(float x) {
598 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500599 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700600 // void map() {
601 // sphere(1.0);
602 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500603 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700604 // void main() {
605 // for (int i = 0; i < 1; i++) {
606 // map();
607 // }
608 // }
609 //
Greg Daniel64773e62016-11-22 09:44:03 -0500610 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
611 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700612 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
613 // the spec makes this make sense.
614// if (is_out(function->fParameters[i])) {
ethannicholasd598f792016-07-25 10:08:54 -0700615 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -0700616 SpvStorageClassFunction));
617// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700618// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700619// }
620 }
621 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
622 this->writeWord(result, fConstantBuffer);
623 this->writeWord(returnType, fConstantBuffer);
624 for (SpvId id : parameterTypes) {
625 this->writeWord(id, fConstantBuffer);
626 }
627 fTypeMap[key] = result;
628 return result;
629 }
630 return entry->second;
631}
632
ethannicholas8ac838d2016-11-22 08:39:36 -0800633SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
634 return this->getPointerType(type, fDefaultLayout, storageClass);
635}
636
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400637SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700638 SpvStorageClass_ storageClass) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400639 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400640 String key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700641 auto entry = fTypeMap.find(key);
642 if (entry == fTypeMap.end()) {
643 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500644 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700645 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700646 fTypeMap[key] = result;
647 return result;
648 }
649 return entry->second;
650}
651
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400652SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700653 switch (expr.fKind) {
654 case Expression::kBinary_Kind:
655 return this->writeBinaryExpression((BinaryExpression&) expr, out);
656 case Expression::kBoolLiteral_Kind:
657 return this->writeBoolLiteral((BoolLiteral&) expr);
658 case Expression::kConstructor_Kind:
659 return this->writeConstructor((Constructor&) expr, out);
660 case Expression::kIntLiteral_Kind:
661 return this->writeIntLiteral((IntLiteral&) expr);
662 case Expression::kFieldAccess_Kind:
663 return this->writeFieldAccess(((FieldAccess&) expr), out);
664 case Expression::kFloatLiteral_Kind:
665 return this->writeFloatLiteral(((FloatLiteral&) expr));
666 case Expression::kFunctionCall_Kind:
667 return this->writeFunctionCall((FunctionCall&) expr, out);
668 case Expression::kPrefix_Kind:
669 return this->writePrefixExpression((PrefixExpression&) expr, out);
670 case Expression::kPostfix_Kind:
671 return this->writePostfixExpression((PostfixExpression&) expr, out);
672 case Expression::kSwizzle_Kind:
673 return this->writeSwizzle((Swizzle&) expr, out);
674 case Expression::kVariableReference_Kind:
675 return this->writeVariableReference((VariableReference&) expr, out);
676 case Expression::kTernary_Kind:
677 return this->writeTernaryExpression((TernaryExpression&) expr, out);
678 case Expression::kIndex_Kind:
679 return this->writeIndexExpression((IndexExpression&) expr, out);
680 default:
681 ABORT("unsupported expression: %s", expr.description().c_str());
682 }
683 return -1;
684}
685
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400686SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700687 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400688 SkASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -0700689 int32_t intrinsicId;
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400690 if (c.fArguments.size() > 0) {
691 const Type& type = c.fArguments[0]->fType;
692 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
693 intrinsicId = std::get<1>(intrinsic->second);
694 } else if (is_signed(fContext, type)) {
695 intrinsicId = std::get<2>(intrinsic->second);
696 } else if (is_unsigned(fContext, type)) {
697 intrinsicId = std::get<3>(intrinsic->second);
698 } else if (is_bool(fContext, type)) {
699 intrinsicId = std::get<4>(intrinsic->second);
700 } else {
701 intrinsicId = std::get<1>(intrinsic->second);
702 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700703 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400704 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700705 }
706 switch (std::get<0>(intrinsic->second)) {
707 case kGLSL_STD_450_IntrinsicKind: {
708 SpvId result = this->nextId();
709 std::vector<SpvId> arguments;
710 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400711 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
712 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
713 } else {
714 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
715 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700716 }
717 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700718 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700719 this->writeWord(result, out);
720 this->writeWord(fGLSLExtendedInstructions, out);
721 this->writeWord(intrinsicId, out);
722 for (SpvId id : arguments) {
723 this->writeWord(id, out);
724 }
725 return result;
726 }
727 case kSPIRV_IntrinsicKind: {
728 SpvId result = this->nextId();
729 std::vector<SpvId> arguments;
730 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400731 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
732 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
733 } else {
734 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
735 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700736 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400737 if (c.fType != *fContext.fVoid_Type) {
738 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
739 this->writeWord(this->getType(c.fType), out);
740 this->writeWord(result, out);
741 } else {
742 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
743 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700744 for (SpvId id : arguments) {
745 this->writeWord(id, out);
746 }
747 return result;
748 }
749 case kSpecial_IntrinsicKind:
750 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
751 default:
752 ABORT("unsupported intrinsic kind");
753 }
754}
755
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500756std::vector<SpvId> SPIRVCodeGenerator::vectorize(
757 const std::vector<std::unique_ptr<Expression>>& args,
758 OutputStream& out) {
759 int vectorSize = 0;
760 for (const auto& a : args) {
761 if (a->fType.kind() == Type::kVector_Kind) {
762 if (vectorSize) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400763 SkASSERT(a->fType.columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500764 }
765 else {
766 vectorSize = a->fType.columns();
767 }
768 }
769 }
770 std::vector<SpvId> result;
771 for (const auto& a : args) {
772 SpvId raw = this->writeExpression(*a, out);
773 if (vectorSize && a->fType.kind() == Type::kScalar_Kind) {
774 SpvId vector = this->nextId();
775 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
776 this->writeWord(this->getType(a->fType.toCompound(fContext, vectorSize, 1)), out);
777 this->writeWord(vector, out);
778 for (int i = 0; i < vectorSize; i++) {
779 this->writeWord(raw, out);
780 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400781 this->writePrecisionModifier(a->fType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500782 result.push_back(vector);
783 } else {
784 result.push_back(raw);
785 }
786 }
787 return result;
788}
789
790void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
791 SpvId signedInst, SpvId unsignedInst,
792 const std::vector<SpvId>& args,
793 OutputStream& out) {
794 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
795 this->writeWord(this->getType(type), out);
796 this->writeWord(id, out);
797 this->writeWord(fGLSLExtendedInstructions, out);
798
799 if (is_float(fContext, type)) {
800 this->writeWord(floatInst, out);
801 } else if (is_signed(fContext, type)) {
802 this->writeWord(signedInst, out);
803 } else if (is_unsigned(fContext, type)) {
804 this->writeWord(unsignedInst, out);
805 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400806 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500807 }
808 for (SpvId a : args) {
809 this->writeWord(a, out);
810 }
811}
812
Greg Daniel64773e62016-11-22 09:44:03 -0500813SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400814 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700815 SpvId result = this->nextId();
816 switch (kind) {
817 case kAtan_SpecialIntrinsic: {
818 std::vector<SpvId> arguments;
819 for (size_t i = 0; i < c.fArguments.size(); i++) {
820 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
821 }
822 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700823 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700824 this->writeWord(result, out);
825 this->writeWord(fGLSLExtendedInstructions, out);
826 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
827 for (SpvId id : arguments) {
828 this->writeWord(id, out);
829 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400830 break;
831 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400832 case kSampledImage_SpecialIntrinsic: {
833 SkASSERT(2 == c.fArguments.size());
834 SpvId img = this->writeExpression(*c.fArguments[0], out);
835 SpvId sampler = this->writeExpression(*c.fArguments[1], out);
836 this->writeInstruction(SpvOpSampledImage,
837 this->getType(c.fType),
838 result,
839 img,
840 sampler,
841 out);
842 break;
843 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400844 case kSubpassLoad_SpecialIntrinsic: {
845 SpvId img = this->writeExpression(*c.fArguments[0], out);
846 std::vector<std::unique_ptr<Expression>> args;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700847 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
848 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
849 Constructor ctor(-1, *fContext.fFloat2_Type, std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400850 SpvId coords = this->writeConstantVector(ctor);
851 if (1 == c.fArguments.size()) {
852 this->writeInstruction(SpvOpImageRead,
853 this->getType(c.fType),
854 result,
855 img,
856 coords,
857 out);
858 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400859 SkASSERT(2 == c.fArguments.size());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400860 SpvId sample = this->writeExpression(*c.fArguments[1], out);
861 this->writeInstruction(SpvOpImageRead,
862 this->getType(c.fType),
863 result,
864 img,
865 coords,
866 SpvImageOperandsSampleMask,
867 sample,
868 out);
869 }
870 break;
871 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700872 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500873 SpvOp_ op = SpvOpImageSampleImplicitLod;
874 switch (c.fArguments[0]->fType.dimensions()) {
875 case SpvDim1D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400876 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500877 op = SpvOpImageSampleProjImplicitLod;
878 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400879 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500880 }
881 break;
882 case SpvDim2D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400883 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500884 op = SpvOpImageSampleProjImplicitLod;
885 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400886 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500887 }
888 break;
889 case SpvDim3D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400890 if (c.fArguments[1]->fType == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500891 op = SpvOpImageSampleProjImplicitLod;
892 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400893 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500894 }
895 break;
896 case SpvDimCube: // fall through
897 case SpvDimRect: // fall through
898 case SpvDimBuffer: // fall through
899 case SpvDimSubpassData:
900 break;
901 }
ethannicholasd598f792016-07-25 10:08:54 -0700902 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700903 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
904 SpvId uv = this->writeExpression(*c.fArguments[1], out);
905 if (c.fArguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500906 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700907 SpvImageOperandsBiasMask,
908 this->writeExpression(*c.fArguments[2], out),
909 out);
910 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400911 SkASSERT(c.fArguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500912 if (fProgram.fSettings.fSharpenTextures) {
913 FloatLiteral lodBias(fContext, -1, -0.5);
914 this->writeInstruction(op, type, result, sampler, uv,
915 SpvImageOperandsBiasMask,
916 this->writeFloatLiteral(lodBias),
917 out);
918 } else {
919 this->writeInstruction(op, type, result, sampler, uv,
920 out);
921 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700922 }
923 break;
924 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500925 case kMod_SpecialIntrinsic: {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500926 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400927 SkASSERT(args.size() == 2);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500928 const Type& operandType = c.fArguments[0]->fType;
929 SpvOp_ op;
930 if (is_float(fContext, operandType)) {
931 op = SpvOpFMod;
932 } else if (is_signed(fContext, operandType)) {
933 op = SpvOpSMod;
934 } else if (is_unsigned(fContext, operandType)) {
935 op = SpvOpUMod;
936 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400937 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500938 return 0;
939 }
940 this->writeOpCode(op, 5, out);
941 this->writeWord(this->getType(operandType), out);
942 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500943 this->writeWord(args[0], out);
944 this->writeWord(args[1], out);
945 break;
946 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700947 case kDFdy_SpecialIntrinsic: {
948 SpvId fn = this->writeExpression(*c.fArguments[0], out);
949 this->writeOpCode(SpvOpDPdy, 4, out);
950 this->writeWord(this->getType(c.fType), out);
951 this->writeWord(result, out);
952 this->writeWord(fn, out);
953 if (fProgram.fSettings.fFlipY) {
954 // Flipping Y also negates the Y derivatives.
955 SpvId flipped = this->nextId();
956 this->writeInstruction(SpvOpFNegate, this->getType(c.fType), flipped, result, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -0400957 this->writePrecisionModifier(c.fType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700958 return flipped;
959 }
960 break;
961 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500962 case kClamp_SpecialIntrinsic: {
963 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400964 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500965 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
966 GLSLstd450UClamp, args, out);
967 break;
968 }
969 case kMax_SpecialIntrinsic: {
970 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400971 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500972 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMax, GLSLstd450SMax,
973 GLSLstd450UMax, args, out);
974 break;
975 }
976 case kMin_SpecialIntrinsic: {
977 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400978 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500979 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMin, GLSLstd450SMin,
980 GLSLstd450UMin, args, out);
981 break;
982 }
983 case kMix_SpecialIntrinsic: {
984 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400985 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500986 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMix, SpvOpUndef,
987 SpvOpUndef, args, out);
988 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500989 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400990 case kSaturate_SpecialIntrinsic: {
991 SkASSERT(c.fArguments.size() == 1);
992 std::vector<std::unique_ptr<Expression>> finalArgs;
993 finalArgs.push_back(c.fArguments[0]->clone());
994 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 0));
995 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 1));
996 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
997 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
998 GLSLstd450UClamp, spvArgs, out);
999 break;
1000 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001001 }
1002 return result;
1003}
1004
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001005SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001006 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07001007 if (entry == fFunctionMap.end()) {
1008 return this->writeIntrinsicCall(c, out);
1009 }
1010 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001011 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
ethannicholasb3058bd2016-07-01 08:22:01 -07001012 std::vector<SpvId> arguments;
1013 for (size_t i = 0; i < c.fArguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001014 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001015 // passed directly
1016 SpvId tmpVar;
1017 // if we need a temporary var to store this argument, this is the value to store in the var
1018 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -07001019 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001020 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
1021 SpvId ptr = lv->getPointer();
1022 if (ptr) {
1023 arguments.push_back(ptr);
1024 continue;
1025 } else {
1026 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1027 // copy it into a temp, call the function, read the value out of the temp, and then
1028 // update the lvalue.
1029 tmpValueId = lv->load(out);
1030 tmpVar = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001031 lvalues.push_back(std::make_tuple(tmpVar, &c.fArguments[i]->fType, std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001032 }
1033 } else {
1034 // see getFunctionType for an explanation of why we're always using pointer parameters
1035 tmpValueId = this->writeExpression(*c.fArguments[i], out);
1036 tmpVar = this->nextId();
1037 }
Greg Daniel64773e62016-11-22 09:44:03 -05001038 this->writeInstruction(SpvOpVariable,
1039 this->getPointerType(c.fArguments[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -07001040 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001041 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001042 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001043 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001044 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1045 arguments.push_back(tmpVar);
1046 }
1047 SpvId result = this->nextId();
1048 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001049 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001050 this->writeWord(result, out);
1051 this->writeWord(entry->second, out);
1052 for (SpvId id : arguments) {
1053 this->writeWord(id, out);
1054 }
1055 // now that the call is complete, we may need to update some lvalues with the new values of out
1056 // arguments
1057 for (const auto& tuple : lvalues) {
1058 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001059 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1060 out);
1061 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001062 std::get<2>(tuple)->store(load, out);
1063 }
1064 return result;
1065}
1066
ethannicholasf789b382016-08-03 12:43:36 -07001067SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001068 SkASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001069 SpvId result = this->nextId();
1070 std::vector<SpvId> arguments;
1071 for (size_t i = 0; i < c.fArguments.size(); i++) {
1072 arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1073 }
ethannicholasd598f792016-07-25 10:08:54 -07001074 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001075 if (c.fArguments.size() == 1) {
1076 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001077 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001078 this->writeWord(type, fConstantBuffer);
1079 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001080 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001081 this->writeWord(arguments[0], fConstantBuffer);
1082 }
1083 } else {
Greg Daniel64773e62016-11-22 09:44:03 -05001084 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001085 fConstantBuffer);
1086 this->writeWord(type, fConstantBuffer);
1087 this->writeWord(result, fConstantBuffer);
1088 for (SpvId id : arguments) {
1089 this->writeWord(id, fConstantBuffer);
1090 }
1091 }
1092 return result;
1093}
1094
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001095SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001096 SkASSERT(c.fType.isFloat());
1097 SkASSERT(c.fArguments.size() == 1);
1098 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001099 SpvId result = this->nextId();
1100 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001101 if (c.fArguments[0]->fType.isSigned()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001102 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001103 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001104 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001105 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Greg Daniel64773e62016-11-22 09:44:03 -05001106 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001107 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001108 }
1109 return result;
1110}
1111
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001112SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001113 SkASSERT(c.fType.isSigned());
1114 SkASSERT(c.fArguments.size() == 1);
1115 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001116 SpvId result = this->nextId();
1117 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001118 if (c.fArguments[0]->fType.isFloat()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001119 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001120 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001121 }
1122 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001123 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001124 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001125 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001126 }
1127 return result;
1128}
1129
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001130SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001131 SkASSERT(c.fType.isUnsigned());
1132 SkASSERT(c.fArguments.size() == 1);
1133 SkASSERT(c.fArguments[0]->fType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001134 SpvId result = this->nextId();
1135 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001136 if (c.fArguments[0]->fType.isFloat()) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001137 this->writeInstruction(SpvOpConvertFToU, this->getType(c.fType), result, parameter,
1138 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001139 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001140 SkASSERT(c.fArguments[0]->fType.isSigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001141 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
1142 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001143 }
1144 return result;
1145}
1146
Ethan Nicholas84645e32017-02-09 13:57:14 -05001147void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001148 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001149 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001150 SpvId zeroId = this->writeFloatLiteral(zero);
1151 std::vector<SpvId> columnIds;
1152 for (int column = 0; column < type.columns(); column++) {
1153 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1154 out);
1155 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1156 out);
1157 SpvId columnId = this->nextId();
1158 this->writeWord(columnId, out);
1159 columnIds.push_back(columnId);
1160 for (int row = 0; row < type.columns(); row++) {
1161 this->writeWord(row == column ? diagonal : zeroId, out);
1162 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001163 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001164 }
1165 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1166 out);
1167 this->writeWord(this->getType(type), out);
1168 this->writeWord(id, out);
1169 for (SpvId id : columnIds) {
1170 this->writeWord(id, out);
1171 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001172 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001173}
1174
1175void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001176 const Type& dstType, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001177 SkASSERT(srcType.kind() == Type::kMatrix_Kind);
1178 SkASSERT(dstType.kind() == Type::kMatrix_Kind);
1179 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001180 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1181 srcType.rows(),
1182 1));
1183 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1184 dstType.rows(),
1185 1));
1186 SpvId zeroId;
1187 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001188 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001189 zeroId = this->writeFloatLiteral(zero);
1190 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001191 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001192 zeroId = this->writeIntLiteral(zero);
1193 } else {
1194 ABORT("unsupported matrix component type");
1195 }
1196 SpvId zeroColumn = 0;
1197 SpvId columns[4];
1198 for (int i = 0; i < dstType.columns(); i++) {
1199 if (i < srcType.columns()) {
1200 // we're still inside the src matrix, copy the column
1201 SpvId srcColumn = this->nextId();
1202 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001203 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001204 SpvId dstColumn;
1205 if (srcType.rows() == dstType.rows()) {
1206 // columns are equal size, don't need to do anything
1207 dstColumn = srcColumn;
1208 }
1209 else if (dstType.rows() > srcType.rows()) {
1210 // dst column is bigger, need to zero-pad it
1211 dstColumn = this->nextId();
1212 int delta = dstType.rows() - srcType.rows();
1213 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1214 this->writeWord(dstColumnType, out);
1215 this->writeWord(dstColumn, out);
1216 this->writeWord(srcColumn, out);
1217 for (int i = 0; i < delta; ++i) {
1218 this->writeWord(zeroId, out);
1219 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001220 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001221 }
1222 else {
1223 // dst column is smaller, need to swizzle the src column
1224 dstColumn = this->nextId();
1225 int count = dstType.rows();
1226 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1227 this->writeWord(dstColumnType, out);
1228 this->writeWord(dstColumn, out);
1229 this->writeWord(srcColumn, out);
1230 this->writeWord(srcColumn, out);
1231 for (int i = 0; i < count; i++) {
1232 this->writeWord(i, out);
1233 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001234 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001235 }
1236 columns[i] = dstColumn;
1237 } else {
1238 // we're past the end of the src matrix, need a vector of zeroes
1239 if (!zeroColumn) {
1240 zeroColumn = this->nextId();
1241 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1242 this->writeWord(dstColumnType, out);
1243 this->writeWord(zeroColumn, out);
1244 for (int i = 0; i < dstType.rows(); ++i) {
1245 this->writeWord(zeroId, out);
1246 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001247 this->writePrecisionModifier(dstType, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001248 }
1249 columns[i] = zeroColumn;
1250 }
1251 }
1252 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1253 this->writeWord(this->getType(dstType), out);
1254 this->writeWord(id, out);
1255 for (int i = 0; i < dstType.columns(); i++) {
1256 this->writeWord(columns[i], out);
1257 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001258 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001259}
1260
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001261void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1262 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001263 std::vector<SpvId>* columnIds,
1264 int* currentCount, int rows, SpvId entry,
1265 OutputStream& out) {
1266 SkASSERT(*currentCount < rows);
1267 ++(*currentCount);
1268 currentColumn->push_back(entry);
1269 if (*currentCount == rows) {
1270 *currentCount = 0;
1271 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1272 this->writeWord(columnType, out);
1273 SpvId columnId = this->nextId();
1274 this->writeWord(columnId, out);
1275 columnIds->push_back(columnId);
1276 for (SpvId id : *currentColumn) {
1277 this->writeWord(id, out);
1278 }
1279 currentColumn->clear();
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001280 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001281 }
1282}
1283
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001284SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001285 SkASSERT(c.fType.kind() == Type::kMatrix_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001286 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1287 // an instruction
1288 std::vector<SpvId> arguments;
1289 for (size_t i = 0; i < c.fArguments.size(); i++) {
1290 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1291 }
1292 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001293 int rows = c.fType.rows();
1294 int columns = c.fType.columns();
Ethan Nicholas84645e32017-02-09 13:57:14 -05001295 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1296 this->writeUniformScaleMatrix(result, arguments[0], c.fType, out);
1297 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kMatrix_Kind) {
1298 this->writeMatrixCopy(result, arguments[0], c.fArguments[0]->fType, c.fType, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001299 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kVector_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001300 SkASSERT(c.fType.rows() == 2 && c.fType.columns() == 2);
1301 SkASSERT(c.fArguments[0]->fType.columns() == 4);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001302 SpvId componentType = this->getType(c.fType.componentType());
1303 SpvId v[4];
1304 for (int i = 0; i < 4; ++i) {
1305 v[i] = this->nextId();
1306 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i, out);
1307 }
1308 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, 2, 1));
1309 SpvId column1 = this->nextId();
1310 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1311 SpvId column2 = this->nextId();
1312 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
1313 this->writeInstruction(SpvOpCompositeConstruct, this->getType(c.fType), result, column1,
1314 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001315 } else {
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001316 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001317 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001318 // ids of vectors and scalars we have written to the current column so far
1319 std::vector<SpvId> currentColumn;
1320 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001321 int currentCount = 0;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001322 Precision precision = c.fType.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001323 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001324 if (currentCount == 0 && c.fArguments[i]->fType.kind() == Type::kVector_Kind &&
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001325 c.fArguments[i]->fType.columns() == c.fType.rows()) {
1326 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001327 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001328 } else {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001329 if (c.fArguments[i]->fType.columns() == 1) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001330 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1331 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001332 } else {
1333 SpvId componentType = this->getType(c.fArguments[i]->fType.componentType());
Ethan Nicholas811b9442018-05-11 13:16:03 -04001334 for (int j = 0; j < c.fArguments[i]->fType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001335 SpvId swizzle = this->nextId();
1336 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1337 arguments[i], j, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001338 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1339 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001340 }
1341 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001342 }
1343 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001344 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001345 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001346 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001347 this->writeWord(result, out);
1348 for (SpvId id : columnIds) {
1349 this->writeWord(id, out);
1350 }
1351 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001352 this->writePrecisionModifier(c.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001353 return result;
1354}
1355
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001356SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001357 SkASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001358 if (c.isConstant()) {
1359 return this->writeConstantVector(c);
1360 }
1361 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1362 // an instruction
1363 std::vector<SpvId> arguments;
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001364 for (size_t i = 0; i < c.fArguments.size(); i++) {
1365 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
1366 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1367 // extract the components and convert them in that case manually. On top of that,
1368 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1369 // doesn't handle vector arguments at all, so we always extract vector components and
1370 // pass them into OpCreateComposite individually.
1371 SpvId vec = this->writeExpression(*c.fArguments[i], out);
1372 SpvOp_ op = SpvOpUndef;
1373 const Type& src = c.fArguments[i]->fType.componentType();
1374 const Type& dst = c.fType.componentType();
1375 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1376 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1377 if (c.fArguments.size() == 1) {
1378 return vec;
1379 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001380 } else if (src == *fContext.fInt_Type ||
1381 src == *fContext.fShort_Type ||
1382 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001383 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001384 } else if (src == *fContext.fUInt_Type ||
1385 src == *fContext.fUShort_Type ||
1386 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001387 op = SpvOpConvertUToF;
1388 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001389 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001390 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001391 } else if (dst == *fContext.fInt_Type ||
1392 dst == *fContext.fShort_Type ||
1393 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001394 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1395 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001396 } else if (src == *fContext.fInt_Type ||
1397 src == *fContext.fShort_Type ||
1398 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001399 if (c.fArguments.size() == 1) {
1400 return vec;
1401 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001402 } else if (src == *fContext.fUInt_Type ||
1403 src == *fContext.fUShort_Type ||
1404 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001405 op = SpvOpBitcast;
1406 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001407 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001408 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001409 } else if (dst == *fContext.fUInt_Type ||
1410 dst == *fContext.fUShort_Type ||
1411 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001412 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1413 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001414 } else if (src == *fContext.fInt_Type ||
1415 src == *fContext.fShort_Type ||
1416 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001417 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001418 } else if (src == *fContext.fUInt_Type ||
1419 src == *fContext.fUShort_Type ||
1420 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001421 if (c.fArguments.size() == 1) {
1422 return vec;
1423 }
1424 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001425 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001426 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001427 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001428 for (int j = 0; j < c.fArguments[i]->fType.columns(); j++) {
1429 SpvId swizzle = this->nextId();
1430 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1431 out);
1432 if (op != SpvOpUndef) {
1433 SpvId cast = this->nextId();
1434 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1435 arguments.push_back(cast);
1436 } else {
1437 arguments.push_back(swizzle);
1438 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001439 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001440 } else {
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001441 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1442 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001443 }
1444 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001445 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1446 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1447 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001448 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001449 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001450 this->writeWord(arguments[0], out);
1451 }
1452 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001453 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001454 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001455 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001456 this->writeWord(result, out);
1457 for (SpvId id : arguments) {
1458 this->writeWord(id, out);
1459 }
1460 }
1461 return result;
1462}
1463
Ethan Nicholasbd553222017-07-18 15:54:59 -04001464SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001465 SkASSERT(c.fType.kind() == Type::kArray_Kind);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001466 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1467 // an instruction
1468 std::vector<SpvId> arguments;
1469 for (size_t i = 0; i < c.fArguments.size(); i++) {
1470 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1471 }
1472 SpvId result = this->nextId();
1473 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
1474 this->writeWord(this->getType(c.fType), out);
1475 this->writeWord(result, out);
1476 for (SpvId id : arguments) {
1477 this->writeWord(id, out);
1478 }
1479 return result;
1480}
1481
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001482SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001483 if (c.fArguments.size() == 1 &&
1484 this->getActualType(c.fType) == this->getActualType(c.fArguments[0]->fType)) {
1485 return this->writeExpression(*c.fArguments[0], out);
1486 }
1487 if (c.fType == *fContext.fFloat_Type || c.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001488 return this->writeFloatConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001489 } else if (c.fType == *fContext.fInt_Type ||
1490 c.fType == *fContext.fShort_Type ||
1491 c.fType == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001492 return this->writeIntConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001493 } else if (c.fType == *fContext.fUInt_Type ||
1494 c.fType == *fContext.fUShort_Type ||
1495 c.fType == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001496 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001497 }
ethannicholasd598f792016-07-25 10:08:54 -07001498 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001499 case Type::kVector_Kind:
1500 return this->writeVectorConstructor(c, out);
1501 case Type::kMatrix_Kind:
1502 return this->writeMatrixConstructor(c, out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001503 case Type::kArray_Kind:
1504 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001505 default:
1506 ABORT("unsupported constructor: %s", c.description().c_str());
1507 }
1508}
1509
1510SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1511 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001512 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001513 return SpvStorageClassInput;
1514 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001515 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001516 return SpvStorageClassOutput;
1517 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001518 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001519 return SpvStorageClassPushConstant;
1520 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001521 return SpvStorageClassUniform;
1522 } else {
1523 return SpvStorageClassFunction;
1524 }
1525}
1526
ethannicholasf789b382016-08-03 12:43:36 -07001527SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001528 switch (expr.fKind) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001529 case Expression::kVariableReference_Kind: {
1530 const Variable& var = ((VariableReference&) expr).fVariable;
1531 if (var.fStorage != Variable::kGlobal_Storage) {
1532 return SpvStorageClassFunction;
1533 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001534 SpvStorageClass_ result = get_storage_class(var.fModifiers);
1535 if (result == SpvStorageClassFunction) {
1536 result = SpvStorageClassPrivate;
1537 }
1538 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001539 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001540 case Expression::kFieldAccess_Kind:
1541 return get_storage_class(*((FieldAccess&) expr).fBase);
1542 case Expression::kIndex_Kind:
1543 return get_storage_class(*((IndexExpression&) expr).fBase);
1544 default:
1545 return SpvStorageClassFunction;
1546 }
1547}
1548
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001549std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001550 std::vector<SpvId> chain;
1551 switch (expr.fKind) {
1552 case Expression::kIndex_Kind: {
1553 IndexExpression& indexExpr = (IndexExpression&) expr;
1554 chain = this->getAccessChain(*indexExpr.fBase, out);
1555 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1556 break;
1557 }
1558 case Expression::kFieldAccess_Kind: {
1559 FieldAccess& fieldExpr = (FieldAccess&) expr;
1560 chain = this->getAccessChain(*fieldExpr.fBase, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001561 IntLiteral index(fContext, -1, fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001562 chain.push_back(this->writeIntLiteral(index));
1563 break;
1564 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001565 default: {
1566 SpvId id = this->getLValue(expr, out)->getPointer();
1567 SkASSERT(id != 0);
1568 chain.push_back(id);
1569 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001570 }
1571 return chain;
1572}
1573
1574class PointerLValue : public SPIRVCodeGenerator::LValue {
1575public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001576 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1577 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001578 : fGen(gen)
1579 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001580 , fType(type)
1581 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001582
1583 virtual SpvId getPointer() override {
1584 return fPointer;
1585 }
1586
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001587 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001588 SpvId result = fGen.nextId();
1589 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001590 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001591 return result;
1592 }
1593
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001594 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001595 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1596 }
1597
1598private:
1599 SPIRVCodeGenerator& fGen;
1600 const SpvId fPointer;
1601 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001602 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001603};
1604
1605class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1606public:
Greg Daniel64773e62016-11-22 09:44:03 -05001607 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001608 const Type& baseType, const Type& swizzleType,
1609 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001610 : fGen(gen)
1611 , fVecPointer(vecPointer)
1612 , fComponents(components)
1613 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001614 , fSwizzleType(swizzleType)
1615 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001616
1617 virtual SpvId getPointer() override {
1618 return 0;
1619 }
1620
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001621 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001622 SpvId base = fGen.nextId();
1623 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001624 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001625 SpvId result = fGen.nextId();
1626 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1627 fGen.writeWord(fGen.getType(fSwizzleType), out);
1628 fGen.writeWord(result, out);
1629 fGen.writeWord(base, out);
1630 fGen.writeWord(base, out);
1631 for (int component : fComponents) {
1632 fGen.writeWord(component, out);
1633 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001634 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001635 return result;
1636 }
1637
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001638 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001639 // use OpVectorShuffle to mix and match the vector components. We effectively create
1640 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001641 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001642 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001643 // float3L = ...;
1644 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001645 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001646 // 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 -07001647 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1648 // (3, 1, 4).
1649 SpvId base = fGen.nextId();
1650 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1651 SpvId shuffle = fGen.nextId();
1652 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1653 fGen.writeWord(fGen.getType(fBaseType), out);
1654 fGen.writeWord(shuffle, out);
1655 fGen.writeWord(base, out);
1656 fGen.writeWord(value, out);
1657 for (int i = 0; i < fBaseType.columns(); i++) {
1658 // current offset into the virtual vector, defaults to pulling the unmodified
1659 // value from the left side
1660 int offset = i;
1661 // check to see if we are writing this component
1662 for (size_t j = 0; j < fComponents.size(); j++) {
1663 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001664 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001665 // the correct component of the right side instead of preserving the
1666 // value from the left
1667 offset = (int) (j + fBaseType.columns());
1668 break;
1669 }
1670 }
1671 fGen.writeWord(offset, out);
1672 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001673 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001674 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1675 }
1676
1677private:
1678 SPIRVCodeGenerator& fGen;
1679 const SpvId fVecPointer;
1680 const std::vector<int>& fComponents;
1681 const Type& fBaseType;
1682 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001683 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001684};
1685
Greg Daniel64773e62016-11-22 09:44:03 -05001686std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001687 OutputStream& out) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001688 Precision precision = expr.fType.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001689 switch (expr.fKind) {
1690 case Expression::kVariableReference_Kind: {
Ethan Nicholas5226b772018-05-03 16:20:41 -04001691 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07001692 const Variable& var = ((VariableReference&) expr).fVariable;
Ethan Nicholas5226b772018-05-03 16:20:41 -04001693 if (var.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
1694 type = this->getType(Type("sk_in", Type::kArray_Kind, var.fType.componentType(),
1695 fSkInCount));
1696 } else {
1697 type = this->getType(expr.fType);
1698 }
ethannicholasd598f792016-07-25 10:08:54 -07001699 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001700 SkASSERT(entry != fVariableMap.end());
Ethan Nicholas5226b772018-05-03 16:20:41 -04001701 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(*this,
1702 entry->second,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001703 type,
1704 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001705 }
1706 case Expression::kIndex_Kind: // fall through
1707 case Expression::kFieldAccess_Kind: {
1708 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1709 SpvId member = this->nextId();
1710 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001711 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001712 this->writeWord(member, out);
1713 for (SpvId idx : chain) {
1714 this->writeWord(idx, out);
1715 }
1716 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -04001717 *this,
1718 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001719 this->getType(expr.fType),
1720 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001721 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001722 case Expression::kSwizzle_Kind: {
1723 Swizzle& swizzle = (Swizzle&) expr;
1724 size_t count = swizzle.fComponents.size();
1725 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001726 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001727 if (count == 1) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001728 IntLiteral index(fContext, -1, swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001729 SpvId member = this->nextId();
1730 this->writeInstruction(SpvOpAccessChain,
Greg Daniel64773e62016-11-22 09:44:03 -05001731 this->getPointerType(swizzle.fType,
1732 get_storage_class(*swizzle.fBase)),
1733 member,
1734 base,
1735 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001736 out);
1737 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1738 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001739 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001740 this->getType(expr.fType),
1741 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001742 } else {
1743 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
Greg Daniel64773e62016-11-22 09:44:03 -05001744 *this,
1745 base,
1746 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001747 swizzle.fBase->fType,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001748 expr.fType,
1749 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001750 }
1751 }
Ethan Nicholasa583b812018-01-18 13:32:11 -05001752 case Expression::kTernary_Kind: {
1753 TernaryExpression& t = (TernaryExpression&) expr;
1754 SpvId test = this->writeExpression(*t.fTest, out);
1755 SpvId end = this->nextId();
1756 SpvId ifTrueLabel = this->nextId();
1757 SpvId ifFalseLabel = this->nextId();
1758 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1759 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1760 this->writeLabel(ifTrueLabel, out);
1761 SpvId ifTrue = this->getLValue(*t.fIfTrue, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001762 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001763 this->writeInstruction(SpvOpBranch, end, out);
1764 ifTrueLabel = fCurrentBlock;
1765 SpvId ifFalse = this->getLValue(*t.fIfFalse, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001766 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001767 ifFalseLabel = fCurrentBlock;
1768 this->writeInstruction(SpvOpBranch, end, out);
1769 SpvId result = this->nextId();
1770 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1771 ifTrueLabel, ifFalse, ifFalseLabel, out);
1772 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1773 *this,
1774 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001775 this->getType(expr.fType),
1776 precision));
Ethan Nicholasa583b812018-01-18 13:32:11 -05001777 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001778 default:
1779 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001780 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001781 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1782 // caught by IRGenerator
1783 SpvId result = this->nextId();
1784 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001785 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1786 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001787 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1788 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1789 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001790 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001791 this->getType(expr.fType),
1792 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001793 }
1794}
1795
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001796SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001797 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001798 auto entry = fVariableMap.find(&ref.fVariable);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001799 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001800 SpvId var = entry->second;
ethannicholasd598f792016-07-25 10:08:54 -07001801 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001802 this->writePrecisionModifier(ref.fVariable.fType, result);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001803 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
1804 fProgram.fSettings.fFlipY) {
1805 // need to remap to a top-left coordinate system
Greg Daniele6ab9982018-08-22 13:56:32 +00001806 if (fRTHeightStructId == (SpvId) -1) {
1807 // height variable hasn't been written yet
1808 std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors));
1809 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
1810 std::vector<Type::Field> fields;
1811 fields.emplace_back(Modifiers(), SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1812 StringFragment name("sksl_synthetic_uniforms");
1813 Type intfStruct(-1, name, fields);
1814 Layout layout(0, -1, -1, 1, -1, -1, -1, -1, Layout::Format::kUnspecified,
1815 Layout::kUnspecified_Primitive, -1, -1, "", Layout::kNo_Key,
Ethan Nicholas78aceb22018-08-31 16:13:58 -04001816 Layout::CType::kDefault);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001817 Variable* intfVar = (Variable*) fSynthetics.takeOwnership(std::unique_ptr<Symbol>(
1818 new Variable(-1,
1819 Modifiers(layout, Modifiers::kUniform_Flag),
1820 name,
1821 intfStruct,
1822 Variable::kGlobal_Storage)));
Greg Daniele6ab9982018-08-22 13:56:32 +00001823 InterfaceBlock intf(-1, intfVar, name, String(""),
1824 std::vector<std::unique_ptr<Expression>>(), st);
1825 fRTHeightStructId = this->writeInterfaceBlock(intf);
1826 fRTHeightFieldIndex = 0;
1827 }
1828 SkASSERT(fRTHeightFieldIndex != (SpvId) -1);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001829 // write float4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, gl_FragCoord.w)
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001830 SpvId xId = this->nextId();
1831 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1832 result, 0, out);
Greg Daniele6ab9982018-08-22 13:56:32 +00001833 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1834 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1835 SpvId heightPtr = this->nextId();
1836 this->writeOpCode(SpvOpAccessChain, 5, out);
1837 this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out);
1838 this->writeWord(heightPtr, out);
1839 this->writeWord(fRTHeightStructId, out);
1840 this->writeWord(fieldIndexId, out);
1841 SpvId heightRead = this->nextId();
1842 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1843 heightPtr, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001844 SpvId rawYId = this->nextId();
1845 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1846 result, 1, out);
1847 SpvId flippedYId = this->nextId();
1848 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
Greg Daniele6ab9982018-08-22 13:56:32 +00001849 heightRead, rawYId, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001850 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001851 SpvId zeroId = writeFloatLiteral(zero);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001852 FloatLiteral one(fContext, -1, 1.0);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001853 SpvId wId = this->nextId();
1854 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), wId,
1855 result, 3, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001856 SpvId flipped = this->nextId();
1857 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001858 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001859 this->writeWord(flipped, out);
1860 this->writeWord(xId, out);
1861 this->writeWord(flippedYId, out);
1862 this->writeWord(zeroId, out);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001863 this->writeWord(wId, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001864 return flipped;
1865 }
Chris Daltonb91c4662018-08-01 10:46:22 -06001866 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
1867 !fProgram.fSettings.fFlipY) {
1868 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1869 // the default convention of "counter-clockwise face is front".
1870 SpvId inverse = this->nextId();
1871 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1872 result, out);
1873 return inverse;
1874 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001875 return result;
1876}
1877
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001878SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001879 if (expr.fBase->fType.kind() == Type::Kind::kVector_Kind) {
1880 SpvId base = this->writeExpression(*expr.fBase, out);
1881 SpvId index = this->writeExpression(*expr.fIndex, out);
1882 SpvId result = this->nextId();
1883 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.fType), result, base,
1884 index, out);
1885 return result;
1886 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001887 return getLValue(expr, out)->load(out);
1888}
1889
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001890SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001891 return getLValue(f, out)->load(out);
1892}
1893
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001894SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001895 SpvId base = this->writeExpression(*swizzle.fBase, out);
1896 SpvId result = this->nextId();
1897 size_t count = swizzle.fComponents.size();
1898 if (count == 1) {
Greg Daniel64773e62016-11-22 09:44:03 -05001899 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
1900 swizzle.fComponents[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001901 } else {
1902 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
ethannicholasd598f792016-07-25 10:08:54 -07001903 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001904 this->writeWord(result, out);
1905 this->writeWord(base, out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001906 SpvId other;
1907 int last = swizzle.fComponents.back();
1908 if (last < 0) {
1909 if (!fConstantZeroOneVector) {
1910 FloatLiteral zero(fContext, -1, 0);
1911 SpvId zeroId = this->writeFloatLiteral(zero);
1912 FloatLiteral one(fContext, -1, 1);
Ethan Nicholas0b2c0542019-02-25 14:29:11 -05001913 SpvId oneId = this->writeFloatLiteral(one);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001914 SpvId type = this->getType(*fContext.fFloat2_Type);
1915 fConstantZeroOneVector = this->nextId();
1916 this->writeOpCode(SpvOpConstantComposite, 5, fConstantBuffer);
1917 this->writeWord(type, fConstantBuffer);
1918 this->writeWord(fConstantZeroOneVector, fConstantBuffer);
1919 this->writeWord(zeroId, fConstantBuffer);
1920 this->writeWord(oneId, fConstantBuffer);
1921 }
1922 other = fConstantZeroOneVector;
1923 } else {
1924 other = base;
1925 }
1926 this->writeWord(other, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001927 for (int component : swizzle.fComponents) {
Ethan Nicholasac285b12019-02-12 16:05:18 -05001928 if (component == SKSL_SWIZZLE_0) {
Ethan Nicholas0b2c0542019-02-25 14:29:11 -05001929 this->writeWord(swizzle.fBase->fType.columns(), out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001930 } else if (component == SKSL_SWIZZLE_1) {
Ethan Nicholas0b2c0542019-02-25 14:29:11 -05001931 this->writeWord(swizzle.fBase->fType.columns() + 1, out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001932 } else {
1933 this->writeWord(component, out);
1934 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001935 }
1936 }
1937 return result;
1938}
1939
Greg Daniel64773e62016-11-22 09:44:03 -05001940SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1941 const Type& operandType, SpvId lhs,
1942 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001943 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001944 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001945 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001946 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001947 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001948 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001949 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001950 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001951 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001952 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001953 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07001954 } else {
1955 ABORT("invalid operandType: %s", operandType.description().c_str());
1956 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04001957 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001958 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
1959 fDecorationBuffer);
1960 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001961 return result;
1962}
1963
Ethan Nicholas48e24052018-03-14 13:51:39 -04001964SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
1965 OutputStream& out) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05001966 if (operandType.kind() == Type::kVector_Kind) {
1967 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001968 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05001969 return result;
1970 }
1971 return id;
1972}
1973
Ethan Nicholas68990be2017-07-13 09:36:52 -04001974SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
1975 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04001976 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04001977 OutputStream& out) {
1978 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001979 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0df21132018-07-10 09:37:51 -04001980 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
1981 operandType.rows(),
1982 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04001983 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04001984 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04001985 1));
1986 SpvId boolType = this->getType(*fContext.fBool_Type);
1987 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04001988 for (int i = 0; i < operandType.columns(); i++) {
1989 SpvId columnL = this->nextId();
1990 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
1991 SpvId columnR = this->nextId();
1992 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04001993 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04001994 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
1995 SpvId merge = this->nextId();
1996 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04001997 if (result != 0) {
1998 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04001999 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002000 result = next;
2001 }
2002 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002003 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04002004 }
2005 }
2006 return result;
2007}
2008
Ethan Nicholas0df21132018-07-10 09:37:51 -04002009SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
2010 SpvId rhs, SpvOp_ floatOperator,
2011 SpvOp_ intOperator,
2012 OutputStream& out) {
2013 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
2014 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
2015 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2016 operandType.rows(),
2017 1));
2018 SpvId columns[4];
2019 for (int i = 0; i < operandType.columns(); i++) {
2020 SpvId columnL = this->nextId();
2021 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2022 SpvId columnR = this->nextId();
2023 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2024 columns[i] = this->nextId();
2025 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2026 }
2027 SpvId result = this->nextId();
2028 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2029 this->writeWord(this->getType(operandType), out);
2030 this->writeWord(result, out);
2031 for (int i = 0; i < operandType.columns(); i++) {
2032 this->writeWord(columns[i], out);
2033 }
2034 return result;
2035}
2036
Ethan Nicholas49465b42019-04-17 12:22:21 -04002037std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2038 if (type.isInteger()) {
2039 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002040 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002041 else if (type.isFloat()) {
2042 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002043 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002044 ABORT("math is unsupported on type '%s'", type.name().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002045 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002046}
2047
2048SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Token::Kind op,
2049 const Type& rightType, SpvId rhs,
2050 const Type& resultType, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002051 Type tmp("<invalid>");
Ethan Nicholas48e24052018-03-14 13:51:39 -04002052 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002053 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002054 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2055 // handling in SPIR-V
Ethan Nicholas49465b42019-04-17 12:22:21 -04002056 if (this->getActualType(leftType) != this->getActualType(rightType)) {
2057 if (leftType.kind() == Type::kVector_Kind && rightType.isNumber()) {
2058 if (op == Token::SLASH) {
2059 SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
2060 SpvId inverse = this->nextId();
2061 this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
2062 rhs = inverse;
2063 op = Token::STAR;
2064 }
2065 if (op == Token::STAR) {
2066 SpvId result = this->nextId();
2067 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2068 result, lhs, rhs, out);
2069 return result;
2070 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002071 // promote number to vector
2072 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002073 const Type& vecType = leftType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002074 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2075 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002076 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002077 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002078 this->writeWord(rhs, out);
2079 }
2080 rhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002081 operandType = &leftType;
2082 } else if (rightType.kind() == Type::kVector_Kind && leftType.isNumber()) {
2083 if (op == Token::STAR) {
2084 SpvId result = this->nextId();
2085 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2086 result, rhs, lhs, out);
2087 return result;
2088 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002089 // promote number to vector
2090 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002091 const Type& vecType = rightType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002092 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2093 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002094 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002095 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002096 this->writeWord(lhs, out);
2097 }
2098 lhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002099 operandType = &rightType;
2100 } else if (leftType.kind() == Type::kMatrix_Kind) {
2101 SpvOp_ spvop;
2102 if (rightType.kind() == Type::kMatrix_Kind) {
2103 spvop = SpvOpMatrixTimesMatrix;
2104 } else if (rightType.kind() == Type::kVector_Kind) {
2105 spvop = SpvOpMatrixTimesVector;
ethannicholasb3058bd2016-07-01 08:22:01 -07002106 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002107 SkASSERT(rightType.kind() == Type::kScalar_Kind);
2108 spvop = SpvOpMatrixTimesScalar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002109 }
2110 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002111 this->writeInstruction(spvop, this->getType(resultType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002112 return result;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002113 } else if (rightType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002114 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002115 if (leftType.kind() == Type::kVector_Kind) {
2116 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(resultType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002117 lhs, rhs, out);
2118 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002119 SkASSERT(leftType.kind() == Type::kScalar_Kind);
2120 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(resultType), result,
2121 rhs, lhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002122 }
2123 return result;
2124 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002125 SkASSERT(false);
2126 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002127 }
2128 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002129 tmp = this->getActualType(leftType);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002130 operandType = &tmp;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002131 SkASSERT(*operandType == this->getActualType(rightType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002132 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002133 switch (op) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002134 case Token::EQEQ: {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002135 if (operandType->kind() == Type::kMatrix_Kind) {
2136 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002137 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002138 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002139 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002140 const Type* tmpType;
2141 if (operandType->kind() == Type::kVector_Kind) {
2142 tmpType = &fContext.fBool_Type->toCompound(fContext,
2143 operandType->columns(),
2144 operandType->rows());
2145 } else {
2146 tmpType = &resultType;
2147 }
2148 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002149 SpvOpFOrdEqual, SpvOpIEqual,
2150 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002151 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002152 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002153 case Token::NEQ:
Ethan Nicholas68990be2017-07-13 09:36:52 -04002154 if (operandType->kind() == Type::kMatrix_Kind) {
2155 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002156 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002157 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002158 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002159 const Type* tmpType;
2160 if (operandType->kind() == Type::kVector_Kind) {
2161 tmpType = &fContext.fBool_Type->toCompound(fContext,
2162 operandType->columns(),
2163 operandType->rows());
2164 } else {
2165 tmpType = &resultType;
2166 }
2167 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002168 SpvOpFOrdNotEqual, SpvOpINotEqual,
2169 SpvOpINotEqual, SpvOpLogicalNotEqual,
2170 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002171 *operandType, SpvOpAny, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002172 case Token::GT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002173 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002174 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2175 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002176 SpvOpUGreaterThan, SpvOpUndef, out);
2177 case Token::LT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002178 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002179 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002180 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
2181 case Token::GTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002182 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002183 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2184 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002185 SpvOpUGreaterThanEqual, SpvOpUndef, out);
2186 case Token::LTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002187 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002188 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2189 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002190 SpvOpULessThanEqual, SpvOpUndef, out);
2191 case Token::PLUS:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002192 if (leftType.kind() == Type::kMatrix_Kind &&
2193 rightType.kind() == Type::kMatrix_Kind) {
2194 SkASSERT(leftType == rightType);
2195 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002196 SpvOpFAdd, SpvOpIAdd, out);
2197 }
Greg Daniel64773e62016-11-22 09:44:03 -05002198 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002199 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2200 case Token::MINUS:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002201 if (leftType.kind() == Type::kMatrix_Kind &&
2202 rightType.kind() == Type::kMatrix_Kind) {
2203 SkASSERT(leftType == rightType);
2204 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002205 SpvOpFSub, SpvOpISub, out);
2206 }
Greg Daniel64773e62016-11-22 09:44:03 -05002207 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002208 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2209 case Token::STAR:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002210 if (leftType.kind() == Type::kMatrix_Kind &&
2211 rightType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002212 // matrix multiply
2213 SpvId result = this->nextId();
2214 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2215 lhs, rhs, out);
2216 return result;
2217 }
Greg Daniel64773e62016-11-22 09:44:03 -05002218 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002219 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2220 case Token::SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002221 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002222 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002223 case Token::PERCENT:
2224 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2225 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002226 case Token::SHL:
2227 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2228 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2229 SpvOpUndef, out);
2230 case Token::SHR:
2231 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2232 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2233 SpvOpUndef, out);
2234 case Token::BITWISEAND:
2235 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2236 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
2237 case Token::BITWISEOR:
2238 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2239 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
2240 case Token::BITWISEXOR:
2241 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2242 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002243 case Token::COMMA:
2244 return rhs;
ethannicholasb3058bd2016-07-01 08:22:01 -07002245 default:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002246 SkASSERT(false);
2247 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002248 }
2249}
2250
Ethan Nicholas49465b42019-04-17 12:22:21 -04002251SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
2252 // handle cases where we don't necessarily evaluate both LHS and RHS
2253 switch (b.fOperator) {
2254 case Token::EQ: {
2255 SpvId rhs = this->writeExpression(*b.fRight, out);
2256 this->getLValue(*b.fLeft, out)->store(rhs, out);
2257 return rhs;
2258 }
2259 case Token::LOGICALAND:
2260 return this->writeLogicalAnd(b, out);
2261 case Token::LOGICALOR:
2262 return this->writeLogicalOr(b, out);
2263 default:
2264 break;
2265 }
2266
2267 std::unique_ptr<LValue> lvalue;
2268 SpvId lhs;
2269 if (is_assignment(b.fOperator)) {
2270 lvalue = this->getLValue(*b.fLeft, out);
2271 lhs = lvalue->load(out);
2272 } else {
2273 lvalue = nullptr;
2274 lhs = this->writeExpression(*b.fLeft, out);
2275 }
2276 SpvId rhs = this->writeExpression(*b.fRight, out);
2277 SpvId result = this->writeBinaryExpression(b.fLeft->fType, lhs, remove_assignment(b.fOperator),
2278 b.fRight->fType, rhs, b.fType, out);
2279 if (lvalue) {
2280 lvalue->store(result, out);
2281 }
2282 return result;
2283}
2284
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002285SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002286 SkASSERT(a.fOperator == Token::LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002287 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002288 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2289 SpvId lhs = this->writeExpression(*a.fLeft, out);
2290 SpvId rhsLabel = this->nextId();
2291 SpvId end = this->nextId();
2292 SpvId lhsBlock = fCurrentBlock;
2293 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2294 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2295 this->writeLabel(rhsLabel, out);
2296 SpvId rhs = this->writeExpression(*a.fRight, out);
2297 SpvId rhsBlock = fCurrentBlock;
2298 this->writeInstruction(SpvOpBranch, end, out);
2299 this->writeLabel(end, out);
2300 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002301 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002302 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002303 return result;
2304}
2305
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002306SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002307 SkASSERT(o.fOperator == Token::LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002308 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002309 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2310 SpvId lhs = this->writeExpression(*o.fLeft, out);
2311 SpvId rhsLabel = this->nextId();
2312 SpvId end = this->nextId();
2313 SpvId lhsBlock = fCurrentBlock;
2314 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2315 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2316 this->writeLabel(rhsLabel, out);
2317 SpvId rhs = this->writeExpression(*o.fRight, out);
2318 SpvId rhsBlock = fCurrentBlock;
2319 this->writeInstruction(SpvOpBranch, end, out);
2320 this->writeLabel(end, out);
2321 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002322 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002323 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002324 return result;
2325}
2326
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002327SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002328 SpvId test = this->writeExpression(*t.fTest, out);
Ethan Nicholas0f21c232018-07-23 09:25:40 -04002329 if (t.fIfTrue->fType.columns() == 1 && t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002330 // both true and false are constants, can just use OpSelect
2331 SpvId result = this->nextId();
2332 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2333 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
Greg Daniel64773e62016-11-22 09:44:03 -05002334 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002335 out);
2336 return result;
2337 }
Greg Daniel64773e62016-11-22 09:44:03 -05002338 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002339 // Adreno. Switched to storing the result in a temp variable as glslang does.
2340 SpvId var = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002341 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002342 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002343 SpvId trueLabel = this->nextId();
2344 SpvId falseLabel = this->nextId();
2345 SpvId end = this->nextId();
2346 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2347 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2348 this->writeLabel(trueLabel, out);
2349 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2350 this->writeInstruction(SpvOpBranch, end, out);
2351 this->writeLabel(falseLabel, out);
2352 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2353 this->writeInstruction(SpvOpBranch, end, out);
2354 this->writeLabel(end, out);
2355 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002356 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002357 this->writePrecisionModifier(t.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002358 return result;
2359}
2360
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002361SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002362 if (p.fOperator == Token::MINUS) {
2363 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002364 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002365 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002366 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002367 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002368 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002369 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2370 } else {
2371 ABORT("unsupported prefix expression %s", p.description().c_str());
Brian Salomon23356442018-11-30 15:33:19 -05002372 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002373 this->writePrecisionModifier(p.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002374 return result;
2375 }
2376 switch (p.fOperator) {
2377 case Token::PLUS:
2378 return this->writeExpression(*p.fOperand, out);
2379 case Token::PLUSPLUS: {
2380 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002381 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002382 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2383 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002384 out);
2385 lv->store(result, out);
2386 return result;
2387 }
2388 case Token::MINUSMINUS: {
2389 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002390 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002391 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2392 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002393 out);
2394 lv->store(result, out);
2395 return result;
2396 }
ethannicholas5961bc92016-10-12 06:39:56 -07002397 case Token::LOGICALNOT: {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002398 SkASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002399 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002400 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002401 this->writeExpression(*p.fOperand, out), out);
2402 return result;
2403 }
ethannicholas5961bc92016-10-12 06:39:56 -07002404 case Token::BITWISENOT: {
2405 SpvId result = this->nextId();
2406 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2407 this->writeExpression(*p.fOperand, out), out);
2408 return result;
2409 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002410 default:
2411 ABORT("unsupported prefix expression: %s", p.description().c_str());
2412 }
2413}
2414
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002415SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002416 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2417 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002418 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002419 switch (p.fOperator) {
2420 case Token::PLUSPLUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002421 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002422 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2423 lv->store(temp, out);
2424 return result;
2425 }
2426 case Token::MINUSMINUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002427 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002428 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2429 lv->store(temp, out);
2430 return result;
2431 }
2432 default:
2433 ABORT("unsupported postfix expression %s", p.description().c_str());
2434 }
2435}
2436
ethannicholasf789b382016-08-03 12:43:36 -07002437SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002438 if (b.fValue) {
2439 if (fBoolTrue == 0) {
2440 fBoolTrue = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002441 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002442 fConstantBuffer);
2443 }
2444 return fBoolTrue;
2445 } else {
2446 if (fBoolFalse == 0) {
2447 fBoolFalse = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002448 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002449 fConstantBuffer);
2450 }
2451 return fBoolFalse;
2452 }
2453}
2454
ethannicholasf789b382016-08-03 12:43:36 -07002455SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002456 ConstantType type;
ethannicholasd598f792016-07-25 10:08:54 -07002457 if (i.fType == *fContext.fInt_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002458 type = ConstantType::kInt;
2459 } else if (i.fType == *fContext.fUInt_Type) {
2460 type = ConstantType::kUInt;
2461 } else if (i.fType == *fContext.fShort_Type) {
2462 type = ConstantType::kShort;
2463 } else if (i.fType == *fContext.fUShort_Type) {
2464 type = ConstantType::kUShort;
ethannicholasb3058bd2016-07-01 08:22:01 -07002465 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002466 std::pair<ConstantValue, ConstantType> key(i.fValue, type);
2467 auto entry = fNumberConstants.find(key);
2468 if (entry == fNumberConstants.end()) {
2469 SpvId result = this->nextId();
2470 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
2471 fConstantBuffer);
2472 fNumberConstants[key] = result;
2473 return result;
2474 }
2475 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002476}
2477
ethannicholasf789b382016-08-03 12:43:36 -07002478SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholase1f55022019-02-05 17:17:40 -05002479 if (f.fType != *fContext.fDouble_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002480 ConstantType type;
2481 if (f.fType == *fContext.fHalf_Type) {
2482 type = ConstantType::kHalf;
2483 } else {
2484 type = ConstantType::kFloat;
2485 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002486 float value = (float) f.fValue;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002487 std::pair<ConstantValue, ConstantType> key(f.fValue, type);
2488 auto entry = fNumberConstants.find(key);
2489 if (entry == fNumberConstants.end()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002490 SpvId result = this->nextId();
2491 uint32_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002492 SkASSERT(sizeof(bits) == sizeof(value));
ethannicholasb3058bd2016-07-01 08:22:01 -07002493 memcpy(&bits, &value, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002494 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
ethannicholasb3058bd2016-07-01 08:22:01 -07002495 fConstantBuffer);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002496 fNumberConstants[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002497 return result;
2498 }
2499 return entry->second;
2500 } else {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002501 std::pair<ConstantValue, ConstantType> key(f.fValue, ConstantType::kDouble);
2502 auto entry = fNumberConstants.find(key);
2503 if (entry == fNumberConstants.end()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002504 SpvId result = this->nextId();
2505 uint64_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002506 SkASSERT(sizeof(bits) == sizeof(f.fValue));
ethannicholasb3058bd2016-07-01 08:22:01 -07002507 memcpy(&bits, &f.fValue, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002508 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002509 bits & 0xffffffff, bits >> 32, fConstantBuffer);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002510 fNumberConstants[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002511 return result;
2512 }
2513 return entry->second;
2514 }
2515}
2516
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002517SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002518 SpvId result = fFunctionMap[&f];
Greg Daniel64773e62016-11-22 09:44:03 -05002519 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002520 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002521 this->writeInstruction(SpvOpName, result, f.fName, fNameBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002522 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002523 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002524 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002525 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002526 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002527 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2528 }
2529 return result;
2530}
2531
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002532SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2533 fVariableBuffer.reset();
ethannicholasb3058bd2016-07-01 08:22:01 -07002534 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2535 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002536 StringStream bodyBuffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04002537 this->writeBlock((Block&) *f.fBody, bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002538 write_stringstream(fVariableBuffer, out);
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002539 if (f.fDeclaration.fName == "main") {
2540 write_stringstream(fGlobalInitializersBuffer, out);
2541 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002542 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002543 if (fCurrentBlock) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002544 if (f.fDeclaration.fReturnType == *fContext.fVoid_Type) {
2545 this->writeInstruction(SpvOpReturn, out);
2546 } else {
2547 this->writeInstruction(SpvOpUnreachable, out);
2548 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002549 }
2550 this->writeInstruction(SpvOpFunctionEnd, out);
2551 return result;
2552}
2553
2554void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2555 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002556 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002557 fDecorationBuffer);
2558 }
2559 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002560 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002561 fDecorationBuffer);
2562 }
2563 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002564 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002565 fDecorationBuffer);
2566 }
2567 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002568 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002569 fDecorationBuffer);
2570 }
Greg Daniel64773e62016-11-22 09:44:03 -05002571 if (layout.fInputAttachmentIndex >= 0) {
2572 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2573 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002574 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002575 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002576 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002577 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002578 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002579 fDecorationBuffer);
2580 }
2581}
2582
2583void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2584 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002585 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002586 layout.fLocation, fDecorationBuffer);
2587 }
2588 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002589 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002590 layout.fBinding, fDecorationBuffer);
2591 }
2592 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002593 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002594 layout.fIndex, fDecorationBuffer);
2595 }
2596 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002597 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002598 layout.fSet, fDecorationBuffer);
2599 }
Greg Daniel64773e62016-11-22 09:44:03 -05002600 if (layout.fInputAttachmentIndex >= 0) {
2601 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2602 layout.fInputAttachmentIndex, fDecorationBuffer);
2603 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002604 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002605 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002606 layout.fBuiltin, fDecorationBuffer);
2607 }
2608}
2609
Ethan Nicholas81d15112018-07-13 12:48:50 -04002610static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2611 switch (m.fLayout.fPrimitive) {
2612 case Layout::kPoints_Primitive:
2613 *outSkInCount = 1;
2614 break;
2615 case Layout::kLines_Primitive:
2616 *outSkInCount = 2;
2617 break;
2618 case Layout::kLinesAdjacency_Primitive:
2619 *outSkInCount = 4;
2620 break;
2621 case Layout::kTriangles_Primitive:
2622 *outSkInCount = 3;
2623 break;
2624 case Layout::kTrianglesAdjacency_Primitive:
2625 *outSkInCount = 6;
2626 break;
2627 default:
2628 return;
2629 }
2630}
2631
ethannicholasf789b382016-08-03 12:43:36 -07002632SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas361941e2017-05-30 15:41:07 -04002633 bool isBuffer = (0 != (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag));
Ethan Nicholas39204fd2017-11-27 13:12:30 -05002634 bool pushConstant = (0 != (intf.fVariable.fModifiers.fLayout.fFlags &
2635 Layout::kPushConstant_Flag));
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002636 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2637 MemoryLayout(MemoryLayout::k430_Standard) :
2638 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002639 SpvId result = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002640 const Type* type = &intf.fVariable.fType;
Greg Daniele6ab9982018-08-22 13:56:32 +00002641 if (fProgram.fInputs.fRTHeight) {
2642 SkASSERT(fRTHeightStructId == (SpvId) -1);
2643 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002644 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002645 fRTHeightStructId = result;
2646 fRTHeightFieldIndex = fields.size();
2647 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002648 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002649 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002650 SpvId typeId;
2651 if (intf.fVariable.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2652 for (const auto& e : fProgram) {
2653 if (e.fKind == ProgramElement::kModifiers_Kind) {
2654 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholas81d15112018-07-13 12:48:50 -04002655 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002656 }
2657 }
2658 typeId = this->getType(Type("sk_in", Type::kArray_Kind, intf.fVariable.fType.componentType(),
2659 fSkInCount), memoryLayout);
2660 } else {
2661 typeId = this->getType(*type, memoryLayout);
2662 }
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002663 if (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag) {
2664 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002665 } else if (intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
2666 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002667 }
ethannicholasd598f792016-07-25 10:08:54 -07002668 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002669 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002670 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002671 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002672 Layout layout = intf.fVariable.fModifiers.fLayout;
2673 if (intf.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
2674 layout.fSet = 0;
2675 }
2676 this->writeLayout(layout, result);
ethannicholasd598f792016-07-25 10:08:54 -07002677 fVariableMap[&intf.fVariable] = result;
Greg Daniele6ab9982018-08-22 13:56:32 +00002678 if (fProgram.fInputs.fRTHeight) {
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002679 delete type;
2680 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002681 return result;
2682}
2683
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002684void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002685 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2686}
2687
2688void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2689 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002690 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2691 }
2692}
2693
ethannicholas5961bc92016-10-12 06:39:56 -07002694#define BUILTIN_IGNORE 9999
Greg Daniel64773e62016-11-22 09:44:03 -05002695void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002696 OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002697 for (size_t i = 0; i < decl.fVars.size(); i++) {
2698 if (decl.fVars[i]->fKind == Statement::kNop_Kind) {
2699 continue;
2700 }
2701 const VarDeclaration& varDecl = (VarDeclaration&) *decl.fVars[i];
2702 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002703 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2704 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002705 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002706 Modifiers::kWriteOnly_Flag |
2707 Modifiers::kCoherent_Flag |
2708 Modifiers::kVolatile_Flag |
2709 Modifiers::kRestrict_Flag)));
ethannicholas5961bc92016-10-12 06:39:56 -07002710 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2711 continue;
2712 }
2713 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2714 kind != Program::kFragment_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002715 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
ethannicholas5961bc92016-10-12 06:39:56 -07002716 continue;
2717 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05002718 if (!var->fReadCount && !var->fWriteCount &&
ethannicholas14fe8cc2016-09-07 13:37:16 -07002719 !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
2720 Modifiers::kOut_Flag |
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002721 Modifiers::kUniform_Flag |
2722 Modifiers::kBuffer_Flag))) {
ethannicholasd598f792016-07-25 10:08:54 -07002723 // variable is dead and not an input / output var (the Vulkan debug layers complain if
2724 // we elide an interface var, even if it's dead)
ethannicholasb3058bd2016-07-01 08:22:01 -07002725 continue;
2726 }
2727 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002728 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002729 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002730 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002731 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002732 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
Stephen Whiteff5d7a22019-07-26 17:42:06 -04002733 if (var->fType.kind() == Type::kSampler_Kind ||
2734 var->fType.kind() == Type::kSeparateSampler_Kind ||
2735 var->fType.kind() == Type::kTexture_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002736 storageClass = SpvStorageClassUniformConstant;
2737 } else {
2738 storageClass = SpvStorageClassUniform;
2739 }
2740 } else {
2741 storageClass = SpvStorageClassPrivate;
2742 }
2743 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002744 fVariableMap[var] = id;
Ethan Nicholas5226b772018-05-03 16:20:41 -04002745 SpvId type;
2746 if (var->fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2747 type = this->getPointerType(Type("sk_in", Type::kArray_Kind,
2748 var->fType.componentType(), fSkInCount),
2749 storageClass);
2750 } else {
2751 type = this->getPointerType(var->fType, storageClass);
2752 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002753 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002754 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002755 this->writePrecisionModifier(var->fType, id);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002756 if (varDecl.fValue) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002757 SkASSERT(!fCurrentBlock);
ethannicholasf789b382016-08-03 12:43:36 -07002758 fCurrentBlock = -1;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002759 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002760 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002761 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002762 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002763 this->writeLayout(var->fModifiers.fLayout, id);
Ethan Nicholas45b0f152017-07-24 14:36:40 -04002764 if (var->fModifiers.fFlags & Modifiers::kFlat_Flag) {
2765 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2766 }
2767 if (var->fModifiers.fFlags & Modifiers::kNoPerspective_Flag) {
2768 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2769 fDecorationBuffer);
2770 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002771 }
2772}
2773
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002774void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002775 for (const auto& stmt : decl.fVars) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002776 SkASSERT(stmt->fKind == Statement::kVarDeclaration_Kind);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002777 VarDeclaration& varDecl = (VarDeclaration&) *stmt;
2778 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002779 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2780 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002781 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002782 Modifiers::kWriteOnly_Flag |
2783 Modifiers::kCoherent_Flag |
2784 Modifiers::kVolatile_Flag |
2785 Modifiers::kRestrict_Flag)));
ethannicholasb3058bd2016-07-01 08:22:01 -07002786 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002787 fVariableMap[var] = id;
2788 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002789 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002790 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002791 if (varDecl.fValue) {
2792 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002793 this->writeInstruction(SpvOpStore, id, value, out);
2794 }
2795 }
2796}
2797
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002798void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002799 switch (s.fKind) {
Ethan Nicholascb670962017-04-20 19:31:52 -04002800 case Statement::kNop_Kind:
2801 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002802 case Statement::kBlock_Kind:
2803 this->writeBlock((Block&) s, out);
2804 break;
2805 case Statement::kExpression_Kind:
2806 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2807 break;
Greg Daniel64773e62016-11-22 09:44:03 -05002808 case Statement::kReturn_Kind:
ethannicholasb3058bd2016-07-01 08:22:01 -07002809 this->writeReturnStatement((ReturnStatement&) s, out);
2810 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002811 case Statement::kVarDeclarations_Kind:
2812 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002813 break;
2814 case Statement::kIf_Kind:
2815 this->writeIfStatement((IfStatement&) s, out);
2816 break;
2817 case Statement::kFor_Kind:
2818 this->writeForStatement((ForStatement&) s, out);
2819 break;
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002820 case Statement::kWhile_Kind:
2821 this->writeWhileStatement((WhileStatement&) s, out);
2822 break;
2823 case Statement::kDo_Kind:
2824 this->writeDoStatement((DoStatement&) s, out);
2825 break;
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002826 case Statement::kSwitch_Kind:
2827 this->writeSwitchStatement((SwitchStatement&) s, out);
2828 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002829 case Statement::kBreak_Kind:
2830 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2831 break;
2832 case Statement::kContinue_Kind:
2833 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2834 break;
2835 case Statement::kDiscard_Kind:
2836 this->writeInstruction(SpvOpKill, out);
2837 break;
2838 default:
2839 ABORT("unsupported statement: %s", s.description().c_str());
2840 }
2841}
2842
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002843void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002844 for (size_t i = 0; i < b.fStatements.size(); i++) {
2845 this->writeStatement(*b.fStatements[i], out);
2846 }
2847}
2848
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002849void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002850 SpvId test = this->writeExpression(*stmt.fTest, out);
2851 SpvId ifTrue = this->nextId();
2852 SpvId ifFalse = this->nextId();
2853 if (stmt.fIfFalse) {
2854 SpvId end = this->nextId();
2855 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2856 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2857 this->writeLabel(ifTrue, out);
2858 this->writeStatement(*stmt.fIfTrue, out);
2859 if (fCurrentBlock) {
2860 this->writeInstruction(SpvOpBranch, end, out);
2861 }
2862 this->writeLabel(ifFalse, out);
2863 this->writeStatement(*stmt.fIfFalse, out);
2864 if (fCurrentBlock) {
2865 this->writeInstruction(SpvOpBranch, end, out);
2866 }
2867 this->writeLabel(end, out);
2868 } else {
2869 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2870 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2871 this->writeLabel(ifTrue, out);
2872 this->writeStatement(*stmt.fIfTrue, out);
2873 if (fCurrentBlock) {
2874 this->writeInstruction(SpvOpBranch, ifFalse, out);
2875 }
2876 this->writeLabel(ifFalse, out);
2877 }
2878}
2879
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002880void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002881 if (f.fInitializer) {
2882 this->writeStatement(*f.fInitializer, out);
2883 }
2884 SpvId header = this->nextId();
2885 SpvId start = this->nextId();
2886 SpvId body = this->nextId();
2887 SpvId next = this->nextId();
2888 fContinueTarget.push(next);
2889 SpvId end = this->nextId();
2890 fBreakTarget.push(end);
2891 this->writeInstruction(SpvOpBranch, header, out);
2892 this->writeLabel(header, out);
2893 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002894 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002895 this->writeLabel(start, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002896 if (f.fTest) {
2897 SpvId test = this->writeExpression(*f.fTest, out);
2898 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2899 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002900 this->writeLabel(body, out);
2901 this->writeStatement(*f.fStatement, out);
2902 if (fCurrentBlock) {
2903 this->writeInstruction(SpvOpBranch, next, out);
2904 }
2905 this->writeLabel(next, out);
2906 if (f.fNext) {
2907 this->writeExpression(*f.fNext, out);
2908 }
2909 this->writeInstruction(SpvOpBranch, header, out);
2910 this->writeLabel(end, out);
2911 fBreakTarget.pop();
2912 fContinueTarget.pop();
2913}
2914
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002915void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002916 SpvId header = this->nextId();
2917 SpvId start = this->nextId();
2918 SpvId body = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04002919 SpvId continueTarget = this->nextId();
2920 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002921 SpvId end = this->nextId();
2922 fBreakTarget.push(end);
2923 this->writeInstruction(SpvOpBranch, header, out);
2924 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04002925 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002926 this->writeInstruction(SpvOpBranch, start, out);
2927 this->writeLabel(start, out);
2928 SpvId test = this->writeExpression(*w.fTest, out);
2929 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2930 this->writeLabel(body, out);
2931 this->writeStatement(*w.fStatement, out);
2932 if (fCurrentBlock) {
Ethan Nicholas0d997662019-04-08 09:46:01 -04002933 this->writeInstruction(SpvOpBranch, continueTarget, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002934 }
Ethan Nicholas0d997662019-04-08 09:46:01 -04002935 this->writeLabel(continueTarget, out);
2936 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002937 this->writeLabel(end, out);
2938 fBreakTarget.pop();
2939 fContinueTarget.pop();
2940}
2941
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002942void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002943 // We believe the do loop code below will work, but Skia doesn't actually use them and
2944 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2945 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2946 // message, simply remove the error call below to see whether our do loop support actually
2947 // works.
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002948 fErrors.error(d.fOffset, "internal error: do loop support has been disabled in SPIR-V, see "
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002949 "SkSLSPIRVCodeGenerator.cpp for details");
2950
2951 SpvId header = this->nextId();
2952 SpvId start = this->nextId();
2953 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04002954 SpvId continueTarget = this->nextId();
2955 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002956 SpvId end = this->nextId();
2957 fBreakTarget.push(end);
2958 this->writeInstruction(SpvOpBranch, header, out);
2959 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04002960 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002961 this->writeInstruction(SpvOpBranch, start, out);
2962 this->writeLabel(start, out);
2963 this->writeStatement(*d.fStatement, out);
2964 if (fCurrentBlock) {
2965 this->writeInstruction(SpvOpBranch, next, out);
2966 }
2967 this->writeLabel(next, out);
2968 SpvId test = this->writeExpression(*d.fTest, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04002969 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
2970 this->writeLabel(continueTarget, out);
2971 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002972 this->writeLabel(end, out);
2973 fBreakTarget.pop();
2974 fContinueTarget.pop();
2975}
2976
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002977void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
2978 SpvId value = this->writeExpression(*s.fValue, out);
2979 std::vector<SpvId> labels;
2980 SpvId end = this->nextId();
2981 SpvId defaultLabel = end;
2982 fBreakTarget.push(end);
2983 int size = 3;
2984 for (const auto& c : s.fCases) {
2985 SpvId label = this->nextId();
2986 labels.push_back(label);
2987 if (c->fValue) {
2988 size += 2;
2989 } else {
2990 defaultLabel = label;
2991 }
2992 }
2993 labels.push_back(end);
2994 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2995 this->writeOpCode(SpvOpSwitch, size, out);
2996 this->writeWord(value, out);
2997 this->writeWord(defaultLabel, out);
2998 for (size_t i = 0; i < s.fCases.size(); ++i) {
2999 if (!s.fCases[i]->fValue) {
3000 continue;
3001 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003002 SkASSERT(s.fCases[i]->fValue->fKind == Expression::kIntLiteral_Kind);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003003 this->writeWord(((IntLiteral&) *s.fCases[i]->fValue).fValue, out);
3004 this->writeWord(labels[i], out);
3005 }
3006 for (size_t i = 0; i < s.fCases.size(); ++i) {
3007 this->writeLabel(labels[i], out);
3008 for (const auto& stmt : s.fCases[i]->fStatements) {
3009 this->writeStatement(*stmt, out);
3010 }
3011 if (fCurrentBlock) {
3012 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3013 }
3014 }
3015 this->writeLabel(end, out);
3016 fBreakTarget.pop();
3017}
3018
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003019void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003020 if (r.fExpression) {
Greg Daniel64773e62016-11-22 09:44:03 -05003021 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003022 out);
3023 } else {
3024 this->writeInstruction(SpvOpReturn, out);
3025 }
3026}
3027
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003028void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003029 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003030 int invocations = 1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003031 for (const auto& e : fProgram) {
3032 if (e.fKind == ProgramElement::kModifiers_Kind) {
3033 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003034 if (m.fFlags & Modifiers::kIn_Flag) {
3035 if (m.fLayout.fInvocations != -1) {
3036 invocations = m.fLayout.fInvocations;
3037 }
3038 SpvId input;
3039 switch (m.fLayout.fPrimitive) {
3040 case Layout::kPoints_Primitive:
3041 input = SpvExecutionModeInputPoints;
3042 break;
3043 case Layout::kLines_Primitive:
3044 input = SpvExecutionModeInputLines;
3045 break;
3046 case Layout::kLinesAdjacency_Primitive:
3047 input = SpvExecutionModeInputLinesAdjacency;
3048 break;
3049 case Layout::kTriangles_Primitive:
3050 input = SpvExecutionModeTriangles;
3051 break;
3052 case Layout::kTrianglesAdjacency_Primitive:
3053 input = SpvExecutionModeInputTrianglesAdjacency;
3054 break;
3055 default:
3056 input = 0;
3057 break;
3058 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003059 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003060 if (input) {
3061 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3062 }
3063 } else if (m.fFlags & Modifiers::kOut_Flag) {
3064 SpvId output;
3065 switch (m.fLayout.fPrimitive) {
3066 case Layout::kPoints_Primitive:
3067 output = SpvExecutionModeOutputPoints;
3068 break;
3069 case Layout::kLineStrip_Primitive:
3070 output = SpvExecutionModeOutputLineStrip;
3071 break;
3072 case Layout::kTriangleStrip_Primitive:
3073 output = SpvExecutionModeOutputTriangleStrip;
3074 break;
3075 default:
3076 output = 0;
3077 break;
3078 }
3079 if (output) {
3080 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3081 }
3082 if (m.fLayout.fMaxVertices != -1) {
3083 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3084 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3085 out);
3086 }
3087 }
3088 }
3089 }
3090 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3091 invocations, out);
3092}
3093
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003094void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003095 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003096 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003097 std::set<SpvId> interfaceVars;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003098 // assign IDs to functions, determine sk_in size
3099 int skInSize = -1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003100 for (const auto& e : program) {
3101 switch (e.fKind) {
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003102 case ProgramElement::kFunction_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003103 FunctionDefinition& f = (FunctionDefinition&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003104 fFunctionMap[&f.fDeclaration] = this->nextId();
3105 break;
3106 }
3107 case ProgramElement::kModifiers_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003108 Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003109 if (m.fFlags & Modifiers::kIn_Flag) {
3110 switch (m.fLayout.fPrimitive) {
3111 case Layout::kPoints_Primitive: // break
3112 case Layout::kLines_Primitive:
3113 skInSize = 1;
3114 break;
3115 case Layout::kLinesAdjacency_Primitive: // break
3116 skInSize = 2;
3117 break;
3118 case Layout::kTriangles_Primitive: // break
3119 case Layout::kTrianglesAdjacency_Primitive:
3120 skInSize = 3;
3121 break;
3122 default:
3123 break;
3124 }
3125 }
3126 break;
3127 }
3128 default:
3129 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003130 }
3131 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003132 for (const auto& e : program) {
3133 if (e.fKind == ProgramElement::kInterfaceBlock_Kind) {
3134 InterfaceBlock& intf = (InterfaceBlock&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003135 if (SK_IN_BUILTIN == intf.fVariable.fModifiers.fLayout.fBuiltin) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003136 SkASSERT(skInSize != -1);
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003137 intf.fSizes.emplace_back(new IntLiteral(fContext, -1, skInSize));
3138 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003139 SpvId id = this->writeInterfaceBlock(intf);
Ethan Nicholas16c11962018-03-16 12:20:54 -04003140 if (((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
3141 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) &&
3142 intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003143 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003144 }
3145 }
3146 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003147 for (const auto& e : program) {
3148 if (e.fKind == ProgramElement::kVar_Kind) {
3149 this->writeGlobalVars(program.fKind, ((VarDeclarations&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003150 }
3151 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003152 for (const auto& e : program) {
3153 if (e.fKind == ProgramElement::kFunction_Kind) {
3154 this->writeFunction(((FunctionDefinition&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003155 }
3156 }
ethannicholasd598f792016-07-25 10:08:54 -07003157 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003158 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07003159 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003160 main = entry.first;
3161 }
3162 }
Ethan Nicholas1a668d22019-04-18 10:37:40 -04003163 if (!main) {
3164 fErrors.error(0, "program does not contain a main() function");
3165 return;
3166 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003167 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003168 const Variable* var = entry.first;
Greg Daniel64773e62016-11-22 09:44:03 -05003169 if (var->fStorage == Variable::kGlobal_Storage &&
Ethan Nicholas16c11962018-03-16 12:20:54 -04003170 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
Ethan Nicholasd23c8192018-09-26 17:01:24 -04003171 (var->fModifiers.fFlags & Modifiers::kOut_Flag))) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003172 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003173 }
3174 }
3175 this->writeCapabilities(out);
3176 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3177 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003178 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->fName.fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003179 (int32_t) interfaceVars.size(), out);
3180 switch (program.fKind) {
3181 case Program::kVertex_Kind:
3182 this->writeWord(SpvExecutionModelVertex, out);
3183 break;
3184 case Program::kFragment_Kind:
3185 this->writeWord(SpvExecutionModelFragment, out);
3186 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003187 case Program::kGeometry_Kind:
3188 this->writeWord(SpvExecutionModelGeometry, out);
3189 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003190 default:
3191 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003192 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003193 SpvId entryPoint = fFunctionMap[main];
3194 this->writeWord(entryPoint, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003195 this->writeString(main->fName.fChars, main->fName.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003196 for (int var : interfaceVars) {
3197 this->writeWord(var, out);
3198 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003199 if (program.fKind == Program::kGeometry_Kind) {
3200 this->writeGeometryShaderExecutionMode(entryPoint, out);
3201 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003202 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003203 this->writeInstruction(SpvOpExecutionMode,
3204 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003205 SpvExecutionModeOriginUpperLeft,
3206 out);
3207 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003208 for (const auto& e : program) {
3209 if (e.fKind == ProgramElement::kExtension_Kind) {
3210 this->writeInstruction(SpvOpSourceExtension, ((Extension&) e).fName.c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003211 }
3212 }
Greg Daniel64773e62016-11-22 09:44:03 -05003213
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003214 write_stringstream(fExtraGlobalsBuffer, out);
3215 write_stringstream(fNameBuffer, out);
3216 write_stringstream(fDecorationBuffer, out);
3217 write_stringstream(fConstantBuffer, out);
3218 write_stringstream(fExternalFunctionsBuffer, out);
3219 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003220}
3221
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003222bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003223 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003224 this->writeWord(SpvMagicNumber, *fOut);
3225 this->writeWord(SpvVersion, *fOut);
3226 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003227 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003228 this->writeInstructions(fProgram, buffer);
3229 this->writeWord(fIdCount, *fOut);
3230 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003231 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003232 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003233}
3234
3235}