blob: c68859424ee6cdc3693b70dc47ba5eea272b43d2 [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
Ethan Nicholas0df1b042017-03-31 13:56:23 -04008#include "SkSLSPIRVCodeGenerator.h"
Ethan Nicholas9bd301d2017-03-31 16:04:34 +00009
ethannicholasb3058bd2016-07-01 08:22:01 -070010#include "GLSL.std.450.h"
11
12#include "ir/SkSLExpressionStatement.h"
13#include "ir/SkSLExtension.h"
14#include "ir/SkSLIndexExpression.h"
15#include "ir/SkSLVariableReference.h"
ethannicholas5961bc92016-10-12 06:39:56 -070016#include "SkSLCompiler.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);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400104 fIntrinsicMap[String("texture")] = SPECIAL(Texture);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400105 fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
Greg Daniel64773e62016-11-22 09:44:03 -0500106
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400107 fIntrinsicMap[String("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400108 SpvOpUndef, SpvOpUndef, SpvOpAny);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400109 fIntrinsicMap[String("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400110 SpvOpUndef, SpvOpUndef, SpvOpAll);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400111 fIntrinsicMap[String("equal")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400112 SpvOpFOrdEqual, SpvOpIEqual,
113 SpvOpIEqual, SpvOpLogicalEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400114 fIntrinsicMap[String("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400115 SpvOpFOrdNotEqual, SpvOpINotEqual,
116 SpvOpINotEqual,
117 SpvOpLogicalNotEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400118 fIntrinsicMap[String("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500119 SpvOpFOrdLessThan, SpvOpSLessThan,
120 SpvOpULessThan, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400121 fIntrinsicMap[String("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500122 SpvOpFOrdLessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400123 SpvOpSLessThanEqual,
124 SpvOpULessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400125 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400126 fIntrinsicMap[String("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500127 SpvOpFOrdGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400128 SpvOpSGreaterThan,
129 SpvOpUGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400130 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400131 fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500132 SpvOpFOrdGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400133 SpvOpSGreaterThanEqual,
134 SpvOpUGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400135 SpvOpUndef);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400136 fIntrinsicMap[String("EmitVertex")] = ALL_SPIRV(EmitVertex);
137 fIntrinsicMap[String("EndPrimitive")] = ALL_SPIRV(EndPrimitive);
ethannicholasb3058bd2016-07-01 08:22:01 -0700138// interpolateAt* not yet supported...
139}
140
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400141void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700142 out.write((const char*) &word, sizeof(word));
ethannicholasb3058bd2016-07-01 08:22:01 -0700143}
144
ethannicholasd598f792016-07-25 10:08:54 -0700145static bool is_float(const Context& context, const Type& type) {
Ethan Nicholas0df21132018-07-10 09:37:51 -0400146 if (type.columns() > 1) {
ethannicholasd598f792016-07-25 10:08:54 -0700147 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700148 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400149 return type == *context.fFloat_Type || type == *context.fHalf_Type ||
150 type == *context.fDouble_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700151}
152
ethannicholasd598f792016-07-25 10:08:54 -0700153static bool is_signed(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700154 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700155 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700156 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400157 return type == *context.fInt_Type || type == *context.fShort_Type ||
158 type == *context.fByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700159}
160
ethannicholasd598f792016-07-25 10:08:54 -0700161static bool is_unsigned(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700162 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700163 return is_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700164 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400165 return type == *context.fUInt_Type || type == *context.fUShort_Type ||
166 type == *context.fUByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700167}
168
ethannicholasd598f792016-07-25 10:08:54 -0700169static bool is_bool(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700170 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700171 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700172 }
ethannicholasd598f792016-07-25 10:08:54 -0700173 return type == *context.fBool_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700174}
175
ethannicholasd598f792016-07-25 10:08:54 -0700176static bool is_out(const Variable& var) {
177 return (var.fModifiers.fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700178}
179
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400180void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400181 SkASSERT(opCode != SpvOpLoad || &out != &fConstantBuffer);
182 SkASSERT(opCode != SpvOpUndef);
ethannicholasb3058bd2016-07-01 08:22:01 -0700183 switch (opCode) {
184 case SpvOpReturn: // fall through
185 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700186 case SpvOpKill: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700187 case SpvOpBranch: // fall through
188 case SpvOpBranchConditional:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400189 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700190 fCurrentBlock = 0;
191 break;
192 case SpvOpConstant: // fall through
193 case SpvOpConstantTrue: // fall through
194 case SpvOpConstantFalse: // fall through
195 case SpvOpConstantComposite: // fall through
196 case SpvOpTypeVoid: // fall through
197 case SpvOpTypeInt: // fall through
198 case SpvOpTypeFloat: // fall through
199 case SpvOpTypeBool: // fall through
200 case SpvOpTypeVector: // fall through
201 case SpvOpTypeMatrix: // fall through
202 case SpvOpTypeArray: // fall through
203 case SpvOpTypePointer: // fall through
204 case SpvOpTypeFunction: // fall through
205 case SpvOpTypeRuntimeArray: // fall through
206 case SpvOpTypeStruct: // fall through
207 case SpvOpTypeImage: // fall through
208 case SpvOpTypeSampledImage: // fall through
209 case SpvOpVariable: // fall through
210 case SpvOpFunction: // fall through
211 case SpvOpFunctionParameter: // fall through
212 case SpvOpFunctionEnd: // fall through
213 case SpvOpExecutionMode: // fall through
214 case SpvOpMemoryModel: // fall through
215 case SpvOpCapability: // fall through
216 case SpvOpExtInstImport: // fall through
217 case SpvOpEntryPoint: // fall through
218 case SpvOpSource: // fall through
219 case SpvOpSourceExtension: // fall through
220 case SpvOpName: // fall through
221 case SpvOpMemberName: // fall through
222 case SpvOpDecorate: // fall through
223 case SpvOpMemberDecorate:
224 break;
225 default:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400226 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700227 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700228 this->writeWord((length << 16) | opCode, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700229}
230
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400231void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700232 fCurrentBlock = label;
233 this->writeInstruction(SpvOpLabel, label, out);
234}
235
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400236void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700237 this->writeOpCode(opCode, 1, out);
238}
239
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400240void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700241 this->writeOpCode(opCode, 2, out);
242 this->writeWord(word1, out);
243}
244
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700245void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputStream& out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400246 out.write(string, length);
ethannicholasb3058bd2016-07-01 08:22:01 -0700247 switch (length % 4) {
248 case 1:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500249 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700250 // fall through
251 case 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500252 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700253 // fall through
254 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500255 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700256 break;
257 default:
258 this->writeWord(0, out);
259 }
260}
261
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700262void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out) {
263 this->writeOpCode(opCode, 1 + (string.fLength + 4) / 4, out);
264 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700265}
266
267
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700268void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400269 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700270 this->writeOpCode(opCode, 2 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700271 this->writeWord(word1, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700272 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700273}
274
Greg Daniel64773e62016-11-22 09:44:03 -0500275void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700276 StringFragment string, OutputStream& out) {
277 this->writeOpCode(opCode, 3 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700278 this->writeWord(word1, out);
279 this->writeWord(word2, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700280 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700281}
282
Greg Daniel64773e62016-11-22 09:44:03 -0500283void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400284 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700285 this->writeOpCode(opCode, 3, out);
286 this->writeWord(word1, out);
287 this->writeWord(word2, out);
288}
289
Greg Daniel64773e62016-11-22 09:44:03 -0500290void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400291 int32_t word3, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700292 this->writeOpCode(opCode, 4, out);
293 this->writeWord(word1, out);
294 this->writeWord(word2, out);
295 this->writeWord(word3, out);
296}
297
Greg Daniel64773e62016-11-22 09:44:03 -0500298void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400299 int32_t word3, int32_t word4, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700300 this->writeOpCode(opCode, 5, out);
301 this->writeWord(word1, out);
302 this->writeWord(word2, out);
303 this->writeWord(word3, out);
304 this->writeWord(word4, out);
305}
306
Greg Daniel64773e62016-11-22 09:44:03 -0500307void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
308 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400309 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700310 this->writeOpCode(opCode, 6, out);
311 this->writeWord(word1, out);
312 this->writeWord(word2, out);
313 this->writeWord(word3, out);
314 this->writeWord(word4, out);
315 this->writeWord(word5, out);
316}
317
Greg Daniel64773e62016-11-22 09:44:03 -0500318void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700319 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400320 int32_t word6, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700321 this->writeOpCode(opCode, 7, out);
322 this->writeWord(word1, out);
323 this->writeWord(word2, out);
324 this->writeWord(word3, out);
325 this->writeWord(word4, out);
326 this->writeWord(word5, out);
327 this->writeWord(word6, out);
328}
329
Greg Daniel64773e62016-11-22 09:44:03 -0500330void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700331 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400332 int32_t word6, int32_t word7, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700333 this->writeOpCode(opCode, 8, out);
334 this->writeWord(word1, out);
335 this->writeWord(word2, out);
336 this->writeWord(word3, out);
337 this->writeWord(word4, out);
338 this->writeWord(word5, out);
339 this->writeWord(word6, out);
340 this->writeWord(word7, out);
341}
342
Greg Daniel64773e62016-11-22 09:44:03 -0500343void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700344 int32_t word3, int32_t word4, int32_t word5,
345 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400346 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700347 this->writeOpCode(opCode, 9, out);
348 this->writeWord(word1, out);
349 this->writeWord(word2, out);
350 this->writeWord(word3, out);
351 this->writeWord(word4, out);
352 this->writeWord(word5, out);
353 this->writeWord(word6, out);
354 this->writeWord(word7, out);
355 this->writeWord(word8, out);
356}
357
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400358void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700359 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
360 if (fCapabilities & bit) {
361 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
362 }
363 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400364 if (fProgram.fKind == Program::kGeometry_Kind) {
365 this->writeInstruction(SpvOpCapability, SpvCapabilityGeometry, out);
366 }
Ethan Nicholas81d15112018-07-13 12:48:50 -0400367 else {
368 this->writeInstruction(SpvOpCapability, SpvCapabilityShader, out);
369 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700370}
371
372SpvId SPIRVCodeGenerator::nextId() {
373 return fIdCount++;
374}
375
Ethan Nicholas19671772016-11-28 16:30:17 -0500376void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
377 SpvId resultId) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700378 this->writeInstruction(SpvOpName, resultId, type.name().c_str(), fNameBuffer);
379 // go ahead and write all of the field types, so we don't inadvertently write them while we're
380 // in the middle of writing the struct instruction
381 std::vector<SpvId> types;
382 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500383 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700384 }
385 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
386 this->writeWord(resultId, fConstantBuffer);
387 for (SpvId id : types) {
388 this->writeWord(id, fConstantBuffer);
389 }
390 size_t offset = 0;
391 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Greg Daniel5155e092019-04-17 15:28:51 +0000392 size_t size = memoryLayout.size(*type.fields()[i].fType);
393 size_t alignment = memoryLayout.alignment(*type.fields()[i].fType);
394 const Layout& fieldLayout = type.fields()[i].fModifiers.fLayout;
Ethan Nicholas19671772016-11-28 16:30:17 -0500395 if (fieldLayout.fOffset >= 0) {
Greg Danieldbd44c72017-01-24 15:12:12 -0500396 if (fieldLayout.fOffset < (int) offset) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700397 fErrors.error(type.fOffset,
Greg Daniel5155e092019-04-17 15:28:51 +0000398 "offset of field '" + type.fields()[i].fName + "' must be at "
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500399 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -0500400 }
401 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700402 fErrors.error(type.fOffset,
Greg Daniel5155e092019-04-17 15:28:51 +0000403 "offset of field '" + type.fields()[i].fName + "' must be a multiple"
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500404 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -0500405 }
406 offset = fieldLayout.fOffset;
407 } else {
408 size_t mod = offset % alignment;
409 if (mod) {
410 offset += alignment - mod;
411 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700412 }
Greg Daniel5155e092019-04-17 15:28:51 +0000413 this->writeInstruction(SpvOpMemberName, resultId, i, type.fields()[i].fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500414 this->writeLayout(fieldLayout, resultId, i);
Greg Daniel5155e092019-04-17 15:28:51 +0000415 if (type.fields()[i].fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -0500416 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700417 (SpvId) offset, fDecorationBuffer);
418 }
Greg Daniel5155e092019-04-17 15:28:51 +0000419 if (type.fields()[i].fType->kind() == Type::kMatrix_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -0500420 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -0700421 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500422 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Greg Daniel5155e092019-04-17 15:28:51 +0000423 (SpvId) memoryLayout.stride(*type.fields()[i].fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800424 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700425 }
426 offset += size;
Greg Daniel5155e092019-04-17 15:28:51 +0000427 Type::Kind kind = type.fields()[i].fType->kind();
ethannicholasb3058bd2016-07-01 08:22:01 -0700428 if ((kind == Type::kArray_Kind || kind == Type::kStruct_Kind) && offset % alignment != 0) {
429 offset += alignment - offset % alignment;
430 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700431 }
432}
433
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400434Type SPIRVCodeGenerator::getActualType(const Type& type) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500435 if (type.isFloat()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400436 return *fContext.fFloat_Type;
437 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500438 if (type.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400439 return *fContext.fInt_Type;
440 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500441 if (type.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400442 return *fContext.fUInt_Type;
443 }
444 if (type.kind() == Type::kMatrix_Kind || type.kind() == Type::kVector_Kind) {
445 if (type.componentType() == *fContext.fHalf_Type) {
446 return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
447 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400448 if (type.componentType() == *fContext.fShort_Type ||
449 type.componentType() == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400450 return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
451 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400452 if (type.componentType() == *fContext.fUShort_Type ||
453 type.componentType() == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400454 return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
455 }
456 }
457 return type;
458}
459
ethannicholasb3058bd2016-07-01 08:22:01 -0700460SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800461 return this->getType(type, fDefaultLayout);
462}
463
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400464SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
465 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400466 String key = type.name() + to_string((int) layout.fStd);
ethannicholas8ac838d2016-11-22 08:39:36 -0800467 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700468 if (entry == fTypeMap.end()) {
469 SpvId result = this->nextId();
470 switch (type.kind()) {
471 case Type::kScalar_Kind:
ethannicholasd598f792016-07-25 10:08:54 -0700472 if (type == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700473 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500474 } else if (type == *fContext.fInt_Type || type == *fContext.fShort_Type ||
475 type == *fContext.fIntLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700476 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500477 } else if (type == *fContext.fUInt_Type || type == *fContext.fUShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700478 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500479 } else if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type ||
480 type == *fContext.fFloatLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700481 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -0700482 } else if (type == *fContext.fDouble_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700483 this->writeInstruction(SpvOpTypeFloat, result, 64, fConstantBuffer);
484 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400485 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700486 }
487 break;
488 case Type::kVector_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500489 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800490 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700491 type.columns(), fConstantBuffer);
492 break;
493 case Type::kMatrix_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500494 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800495 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700496 type.columns(), fConstantBuffer);
497 break;
498 case Type::kStruct_Kind:
ethannicholas8ac838d2016-11-22 08:39:36 -0800499 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700500 break;
501 case Type::kArray_Kind: {
502 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700503 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500504 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800505 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700506 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500507 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400508 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800509 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700510 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400511 SkASSERT(false); // we shouldn't have any runtime-sized arrays right now
Greg Daniel64773e62016-11-22 09:44:03 -0500512 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800513 this->getType(type.componentType(), layout),
514 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400515 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
516 (int32_t) layout.stride(type),
517 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700518 }
519 break;
520 }
521 case Type::kSampler_Kind: {
Greg Daniel64773e62016-11-22 09:44:03 -0500522 SpvId image = result;
523 if (SpvDimSubpassData != type.dimensions()) {
524 image = this->nextId();
525 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400526 if (SpvDimBuffer == type.dimensions()) {
527 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
528 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800529 this->writeInstruction(SpvOpTypeImage, image,
530 this->getType(*fContext.fFloat_Type, layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700531 type.dimensions(), type.isDepth(), type.isArrayed(),
Greg Daniel64773e62016-11-22 09:44:03 -0500532 type.isMultisampled(), type.isSampled() ? 1 : 2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700533 SpvImageFormatUnknown, fConstantBuffer);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400534 fImageTypeMap[key] = image;
Greg Daniel64773e62016-11-22 09:44:03 -0500535 if (SpvDimSubpassData != type.dimensions()) {
536 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
537 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700538 break;
539 }
540 default:
ethannicholasd598f792016-07-25 10:08:54 -0700541 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700542 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
543 } else {
544 ABORT("invalid type: %s", type.description().c_str());
545 }
546 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800547 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700548 return result;
549 }
550 return entry->second;
551}
552
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400553SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400554 SkASSERT(type.kind() == Type::kSampler_Kind);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400555 this->getType(type);
556 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400557 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400558 return fImageTypeMap[key];
559}
560
ethannicholasd598f792016-07-25 10:08:54 -0700561SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400562 String key = function.fReturnType.description() + "(";
563 String separator;
ethannicholasd598f792016-07-25 10:08:54 -0700564 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700565 key += separator;
566 separator = ", ";
ethannicholasd598f792016-07-25 10:08:54 -0700567 key += function.fParameters[i]->fType.description();
ethannicholasb3058bd2016-07-01 08:22:01 -0700568 }
569 key += ")";
570 auto entry = fTypeMap.find(key);
571 if (entry == fTypeMap.end()) {
572 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -0700573 int32_t length = 3 + (int32_t) function.fParameters.size();
574 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700575 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -0700576 for (size_t i = 0; i < function.fParameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500577 // glslang seems to treat all function arguments as pointers whether they need to be or
578 // not. I was initially puzzled by this until I ran bizarre failures with certain
579 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700580 // failure case:
581 //
582 // void sphere(float x) {
583 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500584 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700585 // void map() {
586 // sphere(1.0);
587 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500588 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700589 // void main() {
590 // for (int i = 0; i < 1; i++) {
591 // map();
592 // }
593 // }
594 //
Greg Daniel64773e62016-11-22 09:44:03 -0500595 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
596 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700597 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
598 // the spec makes this make sense.
599// if (is_out(function->fParameters[i])) {
ethannicholasd598f792016-07-25 10:08:54 -0700600 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -0700601 SpvStorageClassFunction));
602// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700603// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700604// }
605 }
606 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
607 this->writeWord(result, fConstantBuffer);
608 this->writeWord(returnType, fConstantBuffer);
609 for (SpvId id : parameterTypes) {
610 this->writeWord(id, fConstantBuffer);
611 }
612 fTypeMap[key] = result;
613 return result;
614 }
615 return entry->second;
616}
617
ethannicholas8ac838d2016-11-22 08:39:36 -0800618SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
619 return this->getPointerType(type, fDefaultLayout, storageClass);
620}
621
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400622SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700623 SpvStorageClass_ storageClass) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400624 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400625 String key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700626 auto entry = fTypeMap.find(key);
627 if (entry == fTypeMap.end()) {
628 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500629 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700630 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700631 fTypeMap[key] = result;
632 return result;
633 }
634 return entry->second;
635}
636
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400637SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700638 switch (expr.fKind) {
639 case Expression::kBinary_Kind:
640 return this->writeBinaryExpression((BinaryExpression&) expr, out);
641 case Expression::kBoolLiteral_Kind:
642 return this->writeBoolLiteral((BoolLiteral&) expr);
643 case Expression::kConstructor_Kind:
644 return this->writeConstructor((Constructor&) expr, out);
645 case Expression::kIntLiteral_Kind:
646 return this->writeIntLiteral((IntLiteral&) expr);
647 case Expression::kFieldAccess_Kind:
648 return this->writeFieldAccess(((FieldAccess&) expr), out);
649 case Expression::kFloatLiteral_Kind:
650 return this->writeFloatLiteral(((FloatLiteral&) expr));
651 case Expression::kFunctionCall_Kind:
652 return this->writeFunctionCall((FunctionCall&) expr, out);
653 case Expression::kPrefix_Kind:
654 return this->writePrefixExpression((PrefixExpression&) expr, out);
655 case Expression::kPostfix_Kind:
656 return this->writePostfixExpression((PostfixExpression&) expr, out);
657 case Expression::kSwizzle_Kind:
658 return this->writeSwizzle((Swizzle&) expr, out);
659 case Expression::kVariableReference_Kind:
660 return this->writeVariableReference((VariableReference&) expr, out);
661 case Expression::kTernary_Kind:
662 return this->writeTernaryExpression((TernaryExpression&) expr, out);
663 case Expression::kIndex_Kind:
664 return this->writeIndexExpression((IndexExpression&) expr, out);
665 default:
666 ABORT("unsupported expression: %s", expr.description().c_str());
667 }
668 return -1;
669}
670
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400671SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700672 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400673 SkASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -0700674 int32_t intrinsicId;
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400675 if (c.fArguments.size() > 0) {
676 const Type& type = c.fArguments[0]->fType;
677 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
678 intrinsicId = std::get<1>(intrinsic->second);
679 } else if (is_signed(fContext, type)) {
680 intrinsicId = std::get<2>(intrinsic->second);
681 } else if (is_unsigned(fContext, type)) {
682 intrinsicId = std::get<3>(intrinsic->second);
683 } else if (is_bool(fContext, type)) {
684 intrinsicId = std::get<4>(intrinsic->second);
685 } else {
686 intrinsicId = std::get<1>(intrinsic->second);
687 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700688 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400689 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700690 }
691 switch (std::get<0>(intrinsic->second)) {
692 case kGLSL_STD_450_IntrinsicKind: {
693 SpvId result = this->nextId();
694 std::vector<SpvId> arguments;
695 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400696 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
697 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
698 } else {
699 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
700 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700701 }
702 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700703 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700704 this->writeWord(result, out);
705 this->writeWord(fGLSLExtendedInstructions, out);
706 this->writeWord(intrinsicId, out);
707 for (SpvId id : arguments) {
708 this->writeWord(id, out);
709 }
710 return result;
711 }
712 case kSPIRV_IntrinsicKind: {
713 SpvId result = this->nextId();
714 std::vector<SpvId> arguments;
715 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400716 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
717 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
718 } else {
719 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
720 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700721 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400722 if (c.fType != *fContext.fVoid_Type) {
723 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
724 this->writeWord(this->getType(c.fType), out);
725 this->writeWord(result, out);
726 } else {
727 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
728 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700729 for (SpvId id : arguments) {
730 this->writeWord(id, out);
731 }
732 return result;
733 }
734 case kSpecial_IntrinsicKind:
735 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
736 default:
737 ABORT("unsupported intrinsic kind");
738 }
739}
740
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500741std::vector<SpvId> SPIRVCodeGenerator::vectorize(
742 const std::vector<std::unique_ptr<Expression>>& args,
743 OutputStream& out) {
744 int vectorSize = 0;
745 for (const auto& a : args) {
746 if (a->fType.kind() == Type::kVector_Kind) {
747 if (vectorSize) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400748 SkASSERT(a->fType.columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500749 }
750 else {
751 vectorSize = a->fType.columns();
752 }
753 }
754 }
755 std::vector<SpvId> result;
756 for (const auto& a : args) {
757 SpvId raw = this->writeExpression(*a, out);
758 if (vectorSize && a->fType.kind() == Type::kScalar_Kind) {
759 SpvId vector = this->nextId();
760 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
761 this->writeWord(this->getType(a->fType.toCompound(fContext, vectorSize, 1)), out);
762 this->writeWord(vector, out);
763 for (int i = 0; i < vectorSize; i++) {
764 this->writeWord(raw, out);
765 }
766 result.push_back(vector);
767 } else {
768 result.push_back(raw);
769 }
770 }
771 return result;
772}
773
774void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
775 SpvId signedInst, SpvId unsignedInst,
776 const std::vector<SpvId>& args,
777 OutputStream& out) {
778 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
779 this->writeWord(this->getType(type), out);
780 this->writeWord(id, out);
781 this->writeWord(fGLSLExtendedInstructions, out);
782
783 if (is_float(fContext, type)) {
784 this->writeWord(floatInst, out);
785 } else if (is_signed(fContext, type)) {
786 this->writeWord(signedInst, out);
787 } else if (is_unsigned(fContext, type)) {
788 this->writeWord(unsignedInst, out);
789 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400790 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500791 }
792 for (SpvId a : args) {
793 this->writeWord(a, out);
794 }
795}
796
Greg Daniel64773e62016-11-22 09:44:03 -0500797SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400798 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700799 SpvId result = this->nextId();
800 switch (kind) {
801 case kAtan_SpecialIntrinsic: {
802 std::vector<SpvId> arguments;
803 for (size_t i = 0; i < c.fArguments.size(); i++) {
804 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
805 }
806 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700807 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700808 this->writeWord(result, out);
809 this->writeWord(fGLSLExtendedInstructions, out);
810 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
811 for (SpvId id : arguments) {
812 this->writeWord(id, out);
813 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400814 break;
815 }
816 case kSubpassLoad_SpecialIntrinsic: {
817 SpvId img = this->writeExpression(*c.fArguments[0], out);
818 std::vector<std::unique_ptr<Expression>> args;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700819 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
820 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
821 Constructor ctor(-1, *fContext.fFloat2_Type, std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400822 SpvId coords = this->writeConstantVector(ctor);
823 if (1 == c.fArguments.size()) {
824 this->writeInstruction(SpvOpImageRead,
825 this->getType(c.fType),
826 result,
827 img,
828 coords,
829 out);
830 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400831 SkASSERT(2 == c.fArguments.size());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400832 SpvId sample = this->writeExpression(*c.fArguments[1], out);
833 this->writeInstruction(SpvOpImageRead,
834 this->getType(c.fType),
835 result,
836 img,
837 coords,
838 SpvImageOperandsSampleMask,
839 sample,
840 out);
841 }
842 break;
843 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700844 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500845 SpvOp_ op = SpvOpImageSampleImplicitLod;
846 switch (c.fArguments[0]->fType.dimensions()) {
847 case SpvDim1D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400848 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500849 op = SpvOpImageSampleProjImplicitLod;
850 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400851 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500852 }
853 break;
854 case SpvDim2D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400855 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500856 op = SpvOpImageSampleProjImplicitLod;
857 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400858 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500859 }
860 break;
861 case SpvDim3D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400862 if (c.fArguments[1]->fType == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500863 op = SpvOpImageSampleProjImplicitLod;
864 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400865 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500866 }
867 break;
868 case SpvDimCube: // fall through
869 case SpvDimRect: // fall through
870 case SpvDimBuffer: // fall through
871 case SpvDimSubpassData:
872 break;
873 }
ethannicholasd598f792016-07-25 10:08:54 -0700874 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700875 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
876 SpvId uv = this->writeExpression(*c.fArguments[1], out);
877 if (c.fArguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500878 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700879 SpvImageOperandsBiasMask,
880 this->writeExpression(*c.fArguments[2], out),
881 out);
882 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400883 SkASSERT(c.fArguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500884 if (fProgram.fSettings.fSharpenTextures) {
885 FloatLiteral lodBias(fContext, -1, -0.5);
886 this->writeInstruction(op, type, result, sampler, uv,
887 SpvImageOperandsBiasMask,
888 this->writeFloatLiteral(lodBias),
889 out);
890 } else {
891 this->writeInstruction(op, type, result, sampler, uv,
892 out);
893 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700894 }
895 break;
896 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500897 case kMod_SpecialIntrinsic: {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500898 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400899 SkASSERT(args.size() == 2);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500900 const Type& operandType = c.fArguments[0]->fType;
901 SpvOp_ op;
902 if (is_float(fContext, operandType)) {
903 op = SpvOpFMod;
904 } else if (is_signed(fContext, operandType)) {
905 op = SpvOpSMod;
906 } else if (is_unsigned(fContext, operandType)) {
907 op = SpvOpUMod;
908 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400909 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500910 return 0;
911 }
912 this->writeOpCode(op, 5, out);
913 this->writeWord(this->getType(operandType), out);
914 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500915 this->writeWord(args[0], out);
916 this->writeWord(args[1], out);
917 break;
918 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700919 case kDFdy_SpecialIntrinsic: {
920 SpvId fn = this->writeExpression(*c.fArguments[0], out);
921 this->writeOpCode(SpvOpDPdy, 4, out);
922 this->writeWord(this->getType(c.fType), out);
923 this->writeWord(result, out);
924 this->writeWord(fn, out);
925 if (fProgram.fSettings.fFlipY) {
926 // Flipping Y also negates the Y derivatives.
927 SpvId flipped = this->nextId();
928 this->writeInstruction(SpvOpFNegate, this->getType(c.fType), flipped, result, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -0400929 this->writePrecisionModifier(c.fType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700930 return flipped;
931 }
932 break;
933 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500934 case kClamp_SpecialIntrinsic: {
935 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400936 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500937 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
938 GLSLstd450UClamp, args, out);
939 break;
940 }
941 case kMax_SpecialIntrinsic: {
942 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400943 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500944 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMax, GLSLstd450SMax,
945 GLSLstd450UMax, args, out);
946 break;
947 }
948 case kMin_SpecialIntrinsic: {
949 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400950 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500951 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMin, GLSLstd450SMin,
952 GLSLstd450UMin, args, out);
953 break;
954 }
955 case kMix_SpecialIntrinsic: {
956 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400957 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500958 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMix, SpvOpUndef,
959 SpvOpUndef, args, out);
960 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500961 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400962 case kSaturate_SpecialIntrinsic: {
963 SkASSERT(c.fArguments.size() == 1);
964 std::vector<std::unique_ptr<Expression>> finalArgs;
965 finalArgs.push_back(c.fArguments[0]->clone());
966 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 0));
967 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 1));
968 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
969 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
970 GLSLstd450UClamp, spvArgs, out);
971 break;
972 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700973 }
974 return result;
975}
976
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400977SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700978 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -0700979 if (entry == fFunctionMap.end()) {
980 return this->writeIntrinsicCall(c, out);
981 }
982 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -0400983 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
ethannicholasb3058bd2016-07-01 08:22:01 -0700984 std::vector<SpvId> arguments;
985 for (size_t i = 0; i < c.fArguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500986 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -0700987 // passed directly
988 SpvId tmpVar;
989 // if we need a temporary var to store this argument, this is the value to store in the var
990 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -0700991 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700992 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
993 SpvId ptr = lv->getPointer();
994 if (ptr) {
995 arguments.push_back(ptr);
996 continue;
997 } else {
998 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
999 // copy it into a temp, call the function, read the value out of the temp, and then
1000 // update the lvalue.
1001 tmpValueId = lv->load(out);
1002 tmpVar = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001003 lvalues.push_back(std::make_tuple(tmpVar, &c.fArguments[i]->fType, std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001004 }
1005 } else {
1006 // see getFunctionType for an explanation of why we're always using pointer parameters
1007 tmpValueId = this->writeExpression(*c.fArguments[i], out);
1008 tmpVar = this->nextId();
1009 }
Greg Daniel64773e62016-11-22 09:44:03 -05001010 this->writeInstruction(SpvOpVariable,
1011 this->getPointerType(c.fArguments[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -07001012 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001013 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001014 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001015 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001016 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1017 arguments.push_back(tmpVar);
1018 }
1019 SpvId result = this->nextId();
1020 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001021 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001022 this->writeWord(result, out);
1023 this->writeWord(entry->second, out);
1024 for (SpvId id : arguments) {
1025 this->writeWord(id, out);
1026 }
1027 // now that the call is complete, we may need to update some lvalues with the new values of out
1028 // arguments
1029 for (const auto& tuple : lvalues) {
1030 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001031 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1032 out);
1033 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001034 std::get<2>(tuple)->store(load, out);
1035 }
1036 return result;
1037}
1038
ethannicholasf789b382016-08-03 12:43:36 -07001039SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001040 SkASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001041 SpvId result = this->nextId();
1042 std::vector<SpvId> arguments;
1043 for (size_t i = 0; i < c.fArguments.size(); i++) {
1044 arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1045 }
ethannicholasd598f792016-07-25 10:08:54 -07001046 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001047 if (c.fArguments.size() == 1) {
1048 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001049 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001050 this->writeWord(type, fConstantBuffer);
1051 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001052 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001053 this->writeWord(arguments[0], fConstantBuffer);
1054 }
1055 } else {
Greg Daniel64773e62016-11-22 09:44:03 -05001056 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001057 fConstantBuffer);
1058 this->writeWord(type, fConstantBuffer);
1059 this->writeWord(result, fConstantBuffer);
1060 for (SpvId id : arguments) {
1061 this->writeWord(id, fConstantBuffer);
1062 }
1063 }
1064 return result;
1065}
1066
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001067SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001068 SkASSERT(c.fType.isFloat());
1069 SkASSERT(c.fArguments.size() == 1);
1070 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001071 SpvId result = this->nextId();
1072 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001073 if (c.fArguments[0]->fType.isSigned()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001074 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001075 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001076 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001077 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Greg Daniel64773e62016-11-22 09:44:03 -05001078 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001079 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001080 }
1081 return result;
1082}
1083
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001084SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001085 SkASSERT(c.fType.isSigned());
1086 SkASSERT(c.fArguments.size() == 1);
1087 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001088 SpvId result = this->nextId();
1089 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001090 if (c.fArguments[0]->fType.isFloat()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001091 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001092 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001093 }
1094 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001095 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001096 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001097 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001098 }
1099 return result;
1100}
1101
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001102SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001103 SkASSERT(c.fType.isUnsigned());
1104 SkASSERT(c.fArguments.size() == 1);
1105 SkASSERT(c.fArguments[0]->fType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001106 SpvId result = this->nextId();
1107 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001108 if (c.fArguments[0]->fType.isFloat()) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001109 this->writeInstruction(SpvOpConvertFToU, this->getType(c.fType), result, parameter,
1110 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001111 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001112 SkASSERT(c.fArguments[0]->fType.isSigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001113 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
1114 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001115 }
1116 return result;
1117}
1118
Ethan Nicholas84645e32017-02-09 13:57:14 -05001119void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001120 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001121 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001122 SpvId zeroId = this->writeFloatLiteral(zero);
1123 std::vector<SpvId> columnIds;
1124 for (int column = 0; column < type.columns(); column++) {
1125 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1126 out);
1127 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1128 out);
1129 SpvId columnId = this->nextId();
1130 this->writeWord(columnId, out);
1131 columnIds.push_back(columnId);
1132 for (int row = 0; row < type.columns(); row++) {
1133 this->writeWord(row == column ? diagonal : zeroId, out);
1134 }
1135 }
1136 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1137 out);
1138 this->writeWord(this->getType(type), out);
1139 this->writeWord(id, out);
1140 for (SpvId id : columnIds) {
1141 this->writeWord(id, out);
1142 }
1143}
1144
1145void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001146 const Type& dstType, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001147 SkASSERT(srcType.kind() == Type::kMatrix_Kind);
1148 SkASSERT(dstType.kind() == Type::kMatrix_Kind);
1149 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001150 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1151 srcType.rows(),
1152 1));
1153 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1154 dstType.rows(),
1155 1));
1156 SpvId zeroId;
1157 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001158 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001159 zeroId = this->writeFloatLiteral(zero);
1160 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001161 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001162 zeroId = this->writeIntLiteral(zero);
1163 } else {
1164 ABORT("unsupported matrix component type");
1165 }
1166 SpvId zeroColumn = 0;
1167 SpvId columns[4];
1168 for (int i = 0; i < dstType.columns(); i++) {
1169 if (i < srcType.columns()) {
1170 // we're still inside the src matrix, copy the column
1171 SpvId srcColumn = this->nextId();
1172 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
1173 SpvId dstColumn;
1174 if (srcType.rows() == dstType.rows()) {
1175 // columns are equal size, don't need to do anything
1176 dstColumn = srcColumn;
1177 }
1178 else if (dstType.rows() > srcType.rows()) {
1179 // dst column is bigger, need to zero-pad it
1180 dstColumn = this->nextId();
1181 int delta = dstType.rows() - srcType.rows();
1182 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1183 this->writeWord(dstColumnType, out);
1184 this->writeWord(dstColumn, out);
1185 this->writeWord(srcColumn, out);
1186 for (int i = 0; i < delta; ++i) {
1187 this->writeWord(zeroId, out);
1188 }
1189 }
1190 else {
1191 // dst column is smaller, need to swizzle the src column
1192 dstColumn = this->nextId();
1193 int count = dstType.rows();
1194 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1195 this->writeWord(dstColumnType, out);
1196 this->writeWord(dstColumn, out);
1197 this->writeWord(srcColumn, out);
1198 this->writeWord(srcColumn, out);
1199 for (int i = 0; i < count; i++) {
1200 this->writeWord(i, out);
1201 }
1202 }
1203 columns[i] = dstColumn;
1204 } else {
1205 // we're past the end of the src matrix, need a vector of zeroes
1206 if (!zeroColumn) {
1207 zeroColumn = this->nextId();
1208 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1209 this->writeWord(dstColumnType, out);
1210 this->writeWord(zeroColumn, out);
1211 for (int i = 0; i < dstType.rows(); ++i) {
1212 this->writeWord(zeroId, out);
1213 }
1214 }
1215 columns[i] = zeroColumn;
1216 }
1217 }
1218 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1219 this->writeWord(this->getType(dstType), out);
1220 this->writeWord(id, out);
1221 for (int i = 0; i < dstType.columns(); i++) {
1222 this->writeWord(columns[i], out);
1223 }
Ethan Nicholas84645e32017-02-09 13:57:14 -05001224}
1225
Greg Daniel5155e092019-04-17 15:28:51 +00001226void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001227 std::vector<SpvId>* columnIds,
1228 int* currentCount, int rows, SpvId entry,
1229 OutputStream& out) {
1230 SkASSERT(*currentCount < rows);
1231 ++(*currentCount);
1232 currentColumn->push_back(entry);
1233 if (*currentCount == rows) {
1234 *currentCount = 0;
1235 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1236 this->writeWord(columnType, out);
1237 SpvId columnId = this->nextId();
1238 this->writeWord(columnId, out);
1239 columnIds->push_back(columnId);
1240 for (SpvId id : *currentColumn) {
1241 this->writeWord(id, out);
1242 }
1243 currentColumn->clear();
1244 }
1245}
1246
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001247SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001248 SkASSERT(c.fType.kind() == Type::kMatrix_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001249 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1250 // an instruction
1251 std::vector<SpvId> arguments;
1252 for (size_t i = 0; i < c.fArguments.size(); i++) {
1253 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1254 }
1255 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001256 int rows = c.fType.rows();
1257 int columns = c.fType.columns();
Ethan Nicholas84645e32017-02-09 13:57:14 -05001258 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1259 this->writeUniformScaleMatrix(result, arguments[0], c.fType, out);
1260 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kMatrix_Kind) {
1261 this->writeMatrixCopy(result, arguments[0], c.fArguments[0]->fType, c.fType, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001262 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kVector_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001263 SkASSERT(c.fType.rows() == 2 && c.fType.columns() == 2);
1264 SkASSERT(c.fArguments[0]->fType.columns() == 4);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001265 SpvId componentType = this->getType(c.fType.componentType());
1266 SpvId v[4];
1267 for (int i = 0; i < 4; ++i) {
1268 v[i] = this->nextId();
1269 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i, out);
1270 }
1271 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, 2, 1));
1272 SpvId column1 = this->nextId();
1273 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1274 SpvId column2 = this->nextId();
1275 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
1276 this->writeInstruction(SpvOpCompositeConstruct, this->getType(c.fType), result, column1,
1277 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001278 } else {
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001279 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001280 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001281 // ids of vectors and scalars we have written to the current column so far
1282 std::vector<SpvId> currentColumn;
1283 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001284 int currentCount = 0;
1285 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001286 if (currentCount == 0 && c.fArguments[i]->fType.kind() == Type::kVector_Kind &&
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001287 c.fArguments[i]->fType.columns() == c.fType.rows()) {
1288 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001289 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001290 } else {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001291 if (c.fArguments[i]->fType.columns() == 1) {
Greg Daniel5155e092019-04-17 15:28:51 +00001292 this->addColumnEntry(columnType, &currentColumn, &columnIds, &currentCount,
1293 rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001294 } else {
1295 SpvId componentType = this->getType(c.fArguments[i]->fType.componentType());
Ethan Nicholas811b9442018-05-11 13:16:03 -04001296 for (int j = 0; j < c.fArguments[i]->fType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001297 SpvId swizzle = this->nextId();
1298 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1299 arguments[i], j, out);
Greg Daniel5155e092019-04-17 15:28:51 +00001300 this->addColumnEntry(columnType, &currentColumn, &columnIds, &currentCount,
1301 rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001302 }
1303 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001304 }
1305 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001306 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001307 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001308 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001309 this->writeWord(result, out);
1310 for (SpvId id : columnIds) {
1311 this->writeWord(id, out);
1312 }
1313 }
1314 return result;
1315}
1316
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001317SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001318 SkASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001319 if (c.isConstant()) {
1320 return this->writeConstantVector(c);
1321 }
1322 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1323 // an instruction
1324 std::vector<SpvId> arguments;
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001325 for (size_t i = 0; i < c.fArguments.size(); i++) {
1326 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
1327 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1328 // extract the components and convert them in that case manually. On top of that,
1329 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1330 // doesn't handle vector arguments at all, so we always extract vector components and
1331 // pass them into OpCreateComposite individually.
1332 SpvId vec = this->writeExpression(*c.fArguments[i], out);
1333 SpvOp_ op = SpvOpUndef;
1334 const Type& src = c.fArguments[i]->fType.componentType();
1335 const Type& dst = c.fType.componentType();
1336 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1337 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1338 if (c.fArguments.size() == 1) {
1339 return vec;
1340 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001341 } else if (src == *fContext.fInt_Type ||
1342 src == *fContext.fShort_Type ||
1343 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001344 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001345 } else if (src == *fContext.fUInt_Type ||
1346 src == *fContext.fUShort_Type ||
1347 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001348 op = SpvOpConvertUToF;
1349 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001350 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001351 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001352 } else if (dst == *fContext.fInt_Type ||
1353 dst == *fContext.fShort_Type ||
1354 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001355 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1356 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001357 } else if (src == *fContext.fInt_Type ||
1358 src == *fContext.fShort_Type ||
1359 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001360 if (c.fArguments.size() == 1) {
1361 return vec;
1362 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001363 } else if (src == *fContext.fUInt_Type ||
1364 src == *fContext.fUShort_Type ||
1365 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001366 op = SpvOpBitcast;
1367 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001368 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001369 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001370 } else if (dst == *fContext.fUInt_Type ||
1371 dst == *fContext.fUShort_Type ||
1372 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001373 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1374 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001375 } else if (src == *fContext.fInt_Type ||
1376 src == *fContext.fShort_Type ||
1377 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001378 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001379 } else if (src == *fContext.fUInt_Type ||
1380 src == *fContext.fUShort_Type ||
1381 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001382 if (c.fArguments.size() == 1) {
1383 return vec;
1384 }
1385 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001386 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001387 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001388 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001389 for (int j = 0; j < c.fArguments[i]->fType.columns(); j++) {
1390 SpvId swizzle = this->nextId();
1391 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1392 out);
1393 if (op != SpvOpUndef) {
1394 SpvId cast = this->nextId();
1395 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1396 arguments.push_back(cast);
1397 } else {
1398 arguments.push_back(swizzle);
1399 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001400 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001401 } else {
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001402 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1403 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001404 }
1405 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001406 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1407 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1408 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001409 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001410 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001411 this->writeWord(arguments[0], out);
1412 }
1413 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001414 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001415 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001416 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001417 this->writeWord(result, out);
1418 for (SpvId id : arguments) {
1419 this->writeWord(id, out);
1420 }
1421 }
1422 return result;
1423}
1424
Ethan Nicholasbd553222017-07-18 15:54:59 -04001425SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001426 SkASSERT(c.fType.kind() == Type::kArray_Kind);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001427 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1428 // an instruction
1429 std::vector<SpvId> arguments;
1430 for (size_t i = 0; i < c.fArguments.size(); i++) {
1431 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1432 }
1433 SpvId result = this->nextId();
1434 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
1435 this->writeWord(this->getType(c.fType), out);
1436 this->writeWord(result, out);
1437 for (SpvId id : arguments) {
1438 this->writeWord(id, out);
1439 }
1440 return result;
1441}
1442
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001443SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001444 if (c.fArguments.size() == 1 &&
1445 this->getActualType(c.fType) == this->getActualType(c.fArguments[0]->fType)) {
1446 return this->writeExpression(*c.fArguments[0], out);
1447 }
1448 if (c.fType == *fContext.fFloat_Type || c.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001449 return this->writeFloatConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001450 } else if (c.fType == *fContext.fInt_Type ||
1451 c.fType == *fContext.fShort_Type ||
1452 c.fType == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001453 return this->writeIntConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001454 } else if (c.fType == *fContext.fUInt_Type ||
1455 c.fType == *fContext.fUShort_Type ||
1456 c.fType == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001457 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001458 }
ethannicholasd598f792016-07-25 10:08:54 -07001459 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001460 case Type::kVector_Kind:
1461 return this->writeVectorConstructor(c, out);
1462 case Type::kMatrix_Kind:
1463 return this->writeMatrixConstructor(c, out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001464 case Type::kArray_Kind:
1465 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001466 default:
1467 ABORT("unsupported constructor: %s", c.description().c_str());
1468 }
1469}
1470
1471SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1472 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001473 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001474 return SpvStorageClassInput;
1475 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001476 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001477 return SpvStorageClassOutput;
1478 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001479 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001480 return SpvStorageClassPushConstant;
1481 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001482 return SpvStorageClassUniform;
1483 } else {
1484 return SpvStorageClassFunction;
1485 }
1486}
1487
ethannicholasf789b382016-08-03 12:43:36 -07001488SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001489 switch (expr.fKind) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001490 case Expression::kVariableReference_Kind: {
1491 const Variable& var = ((VariableReference&) expr).fVariable;
1492 if (var.fStorage != Variable::kGlobal_Storage) {
1493 return SpvStorageClassFunction;
1494 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001495 SpvStorageClass_ result = get_storage_class(var.fModifiers);
1496 if (result == SpvStorageClassFunction) {
1497 result = SpvStorageClassPrivate;
1498 }
1499 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001500 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001501 case Expression::kFieldAccess_Kind:
1502 return get_storage_class(*((FieldAccess&) expr).fBase);
1503 case Expression::kIndex_Kind:
1504 return get_storage_class(*((IndexExpression&) expr).fBase);
1505 default:
1506 return SpvStorageClassFunction;
1507 }
1508}
1509
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001510std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001511 std::vector<SpvId> chain;
1512 switch (expr.fKind) {
1513 case Expression::kIndex_Kind: {
1514 IndexExpression& indexExpr = (IndexExpression&) expr;
1515 chain = this->getAccessChain(*indexExpr.fBase, out);
1516 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1517 break;
1518 }
1519 case Expression::kFieldAccess_Kind: {
1520 FieldAccess& fieldExpr = (FieldAccess&) expr;
1521 chain = this->getAccessChain(*fieldExpr.fBase, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001522 IntLiteral index(fContext, -1, fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001523 chain.push_back(this->writeIntLiteral(index));
1524 break;
1525 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001526 default: {
1527 SpvId id = this->getLValue(expr, out)->getPointer();
1528 SkASSERT(id != 0);
1529 chain.push_back(id);
1530 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001531 }
1532 return chain;
1533}
1534
1535class PointerLValue : public SPIRVCodeGenerator::LValue {
1536public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001537 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1538 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001539 : fGen(gen)
1540 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001541 , fType(type)
1542 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001543
1544 virtual SpvId getPointer() override {
1545 return fPointer;
1546 }
1547
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001548 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001549 SpvId result = fGen.nextId();
1550 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001551 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001552 return result;
1553 }
1554
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001555 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001556 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1557 }
1558
1559private:
1560 SPIRVCodeGenerator& fGen;
1561 const SpvId fPointer;
1562 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001563 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001564};
1565
1566class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1567public:
Greg Daniel64773e62016-11-22 09:44:03 -05001568 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001569 const Type& baseType, const Type& swizzleType,
1570 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001571 : fGen(gen)
1572 , fVecPointer(vecPointer)
1573 , fComponents(components)
1574 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001575 , fSwizzleType(swizzleType)
1576 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001577
1578 virtual SpvId getPointer() override {
1579 return 0;
1580 }
1581
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001582 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001583 SpvId base = fGen.nextId();
1584 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001585 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001586 SpvId result = fGen.nextId();
1587 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1588 fGen.writeWord(fGen.getType(fSwizzleType), out);
1589 fGen.writeWord(result, out);
1590 fGen.writeWord(base, out);
1591 fGen.writeWord(base, out);
1592 for (int component : fComponents) {
1593 fGen.writeWord(component, out);
1594 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001595 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001596 return result;
1597 }
1598
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001599 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001600 // use OpVectorShuffle to mix and match the vector components. We effectively create
1601 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001602 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001603 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001604 // float3L = ...;
1605 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001606 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001607 // 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 -07001608 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1609 // (3, 1, 4).
1610 SpvId base = fGen.nextId();
1611 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1612 SpvId shuffle = fGen.nextId();
1613 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1614 fGen.writeWord(fGen.getType(fBaseType), out);
1615 fGen.writeWord(shuffle, out);
1616 fGen.writeWord(base, out);
1617 fGen.writeWord(value, out);
1618 for (int i = 0; i < fBaseType.columns(); i++) {
1619 // current offset into the virtual vector, defaults to pulling the unmodified
1620 // value from the left side
1621 int offset = i;
1622 // check to see if we are writing this component
1623 for (size_t j = 0; j < fComponents.size(); j++) {
1624 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001625 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001626 // the correct component of the right side instead of preserving the
1627 // value from the left
1628 offset = (int) (j + fBaseType.columns());
1629 break;
1630 }
1631 }
1632 fGen.writeWord(offset, out);
1633 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001634 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001635 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1636 }
1637
1638private:
1639 SPIRVCodeGenerator& fGen;
1640 const SpvId fVecPointer;
1641 const std::vector<int>& fComponents;
1642 const Type& fBaseType;
1643 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001644 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001645};
1646
Greg Daniel64773e62016-11-22 09:44:03 -05001647std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001648 OutputStream& out) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001649 Precision precision = expr.fType.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001650 switch (expr.fKind) {
1651 case Expression::kVariableReference_Kind: {
Ethan Nicholas5226b772018-05-03 16:20:41 -04001652 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07001653 const Variable& var = ((VariableReference&) expr).fVariable;
Ethan Nicholas5226b772018-05-03 16:20:41 -04001654 if (var.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
1655 type = this->getType(Type("sk_in", Type::kArray_Kind, var.fType.componentType(),
1656 fSkInCount));
1657 } else {
1658 type = this->getType(expr.fType);
1659 }
ethannicholasd598f792016-07-25 10:08:54 -07001660 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001661 SkASSERT(entry != fVariableMap.end());
Ethan Nicholas5226b772018-05-03 16:20:41 -04001662 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(*this,
1663 entry->second,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001664 type,
1665 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001666 }
1667 case Expression::kIndex_Kind: // fall through
1668 case Expression::kFieldAccess_Kind: {
1669 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1670 SpvId member = this->nextId();
1671 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001672 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001673 this->writeWord(member, out);
1674 for (SpvId idx : chain) {
1675 this->writeWord(idx, out);
1676 }
1677 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -04001678 *this,
1679 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001680 this->getType(expr.fType),
1681 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001682 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001683 case Expression::kSwizzle_Kind: {
1684 Swizzle& swizzle = (Swizzle&) expr;
1685 size_t count = swizzle.fComponents.size();
1686 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001687 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001688 if (count == 1) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001689 IntLiteral index(fContext, -1, swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001690 SpvId member = this->nextId();
1691 this->writeInstruction(SpvOpAccessChain,
Greg Daniel64773e62016-11-22 09:44:03 -05001692 this->getPointerType(swizzle.fType,
1693 get_storage_class(*swizzle.fBase)),
1694 member,
1695 base,
1696 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001697 out);
1698 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1699 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001700 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001701 this->getType(expr.fType),
1702 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001703 } else {
1704 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
Greg Daniel64773e62016-11-22 09:44:03 -05001705 *this,
1706 base,
1707 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001708 swizzle.fBase->fType,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001709 expr.fType,
1710 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001711 }
1712 }
Ethan Nicholasa583b812018-01-18 13:32:11 -05001713 case Expression::kTernary_Kind: {
1714 TernaryExpression& t = (TernaryExpression&) expr;
1715 SpvId test = this->writeExpression(*t.fTest, out);
1716 SpvId end = this->nextId();
1717 SpvId ifTrueLabel = this->nextId();
1718 SpvId ifFalseLabel = this->nextId();
1719 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1720 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1721 this->writeLabel(ifTrueLabel, out);
1722 SpvId ifTrue = this->getLValue(*t.fIfTrue, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001723 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001724 this->writeInstruction(SpvOpBranch, end, out);
1725 ifTrueLabel = fCurrentBlock;
1726 SpvId ifFalse = this->getLValue(*t.fIfFalse, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001727 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001728 ifFalseLabel = fCurrentBlock;
1729 this->writeInstruction(SpvOpBranch, end, out);
1730 SpvId result = this->nextId();
1731 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1732 ifTrueLabel, ifFalse, ifFalseLabel, out);
1733 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1734 *this,
1735 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001736 this->getType(expr.fType),
1737 precision));
Ethan Nicholasa583b812018-01-18 13:32:11 -05001738 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001739 default:
1740 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001741 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001742 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1743 // caught by IRGenerator
1744 SpvId result = this->nextId();
1745 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001746 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1747 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001748 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1749 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1750 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001751 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001752 this->getType(expr.fType),
1753 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001754 }
1755}
1756
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001757SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001758 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001759 auto entry = fVariableMap.find(&ref.fVariable);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001760 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001761 SpvId var = entry->second;
ethannicholasd598f792016-07-25 10:08:54 -07001762 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001763 this->writePrecisionModifier(ref.fVariable.fType, result);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001764 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
1765 fProgram.fSettings.fFlipY) {
1766 // need to remap to a top-left coordinate system
Greg Daniele6ab9982018-08-22 13:56:32 +00001767 if (fRTHeightStructId == (SpvId) -1) {
1768 // height variable hasn't been written yet
1769 std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors));
1770 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
1771 std::vector<Type::Field> fields;
1772 fields.emplace_back(Modifiers(), SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1773 StringFragment name("sksl_synthetic_uniforms");
1774 Type intfStruct(-1, name, fields);
1775 Layout layout(0, -1, -1, 1, -1, -1, -1, -1, Layout::Format::kUnspecified,
1776 Layout::kUnspecified_Primitive, -1, -1, "", Layout::kNo_Key,
Ethan Nicholas78aceb22018-08-31 16:13:58 -04001777 Layout::CType::kDefault);
Greg Daniele6ab9982018-08-22 13:56:32 +00001778 Variable* intfVar = new Variable(-1,
1779 Modifiers(layout, Modifiers::kUniform_Flag),
1780 name,
1781 intfStruct,
1782 Variable::kGlobal_Storage);
1783 fSynthetics.takeOwnership(intfVar);
1784 InterfaceBlock intf(-1, intfVar, name, String(""),
1785 std::vector<std::unique_ptr<Expression>>(), st);
1786 fRTHeightStructId = this->writeInterfaceBlock(intf);
1787 fRTHeightFieldIndex = 0;
1788 }
1789 SkASSERT(fRTHeightFieldIndex != (SpvId) -1);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001790 // write float4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, gl_FragCoord.w)
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001791 SpvId xId = this->nextId();
1792 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1793 result, 0, out);
Greg Daniele6ab9982018-08-22 13:56:32 +00001794 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1795 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1796 SpvId heightPtr = this->nextId();
1797 this->writeOpCode(SpvOpAccessChain, 5, out);
1798 this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out);
1799 this->writeWord(heightPtr, out);
1800 this->writeWord(fRTHeightStructId, out);
1801 this->writeWord(fieldIndexId, out);
1802 SpvId heightRead = this->nextId();
1803 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1804 heightPtr, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001805 SpvId rawYId = this->nextId();
1806 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1807 result, 1, out);
1808 SpvId flippedYId = this->nextId();
1809 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
Greg Daniele6ab9982018-08-22 13:56:32 +00001810 heightRead, rawYId, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001811 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001812 SpvId zeroId = writeFloatLiteral(zero);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001813 FloatLiteral one(fContext, -1, 1.0);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001814 SpvId wId = this->nextId();
1815 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), wId,
1816 result, 3, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001817 SpvId flipped = this->nextId();
1818 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001819 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001820 this->writeWord(flipped, out);
1821 this->writeWord(xId, out);
1822 this->writeWord(flippedYId, out);
1823 this->writeWord(zeroId, out);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001824 this->writeWord(wId, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001825 return flipped;
1826 }
Chris Daltonb91c4662018-08-01 10:46:22 -06001827 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
1828 !fProgram.fSettings.fFlipY) {
1829 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1830 // the default convention of "counter-clockwise face is front".
1831 SpvId inverse = this->nextId();
1832 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1833 result, out);
1834 return inverse;
1835 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001836 return result;
1837}
1838
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001839SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001840 if (expr.fBase->fType.kind() == Type::Kind::kVector_Kind) {
1841 SpvId base = this->writeExpression(*expr.fBase, out);
1842 SpvId index = this->writeExpression(*expr.fIndex, out);
1843 SpvId result = this->nextId();
1844 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.fType), result, base,
1845 index, out);
1846 return result;
1847 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001848 return getLValue(expr, out)->load(out);
1849}
1850
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001851SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001852 return getLValue(f, out)->load(out);
1853}
1854
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001855SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001856 SpvId base = this->writeExpression(*swizzle.fBase, out);
1857 SpvId result = this->nextId();
1858 size_t count = swizzle.fComponents.size();
1859 if (count == 1) {
Greg Daniel64773e62016-11-22 09:44:03 -05001860 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
1861 swizzle.fComponents[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001862 } else {
1863 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
ethannicholasd598f792016-07-25 10:08:54 -07001864 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001865 this->writeWord(result, out);
1866 this->writeWord(base, out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001867 SpvId other;
1868 int last = swizzle.fComponents.back();
1869 if (last < 0) {
1870 if (!fConstantZeroOneVector) {
1871 FloatLiteral zero(fContext, -1, 0);
1872 SpvId zeroId = this->writeFloatLiteral(zero);
1873 FloatLiteral one(fContext, -1, 1);
Ethan Nicholas0b2c0542019-02-25 14:29:11 -05001874 SpvId oneId = this->writeFloatLiteral(one);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001875 SpvId type = this->getType(*fContext.fFloat2_Type);
1876 fConstantZeroOneVector = this->nextId();
1877 this->writeOpCode(SpvOpConstantComposite, 5, fConstantBuffer);
1878 this->writeWord(type, fConstantBuffer);
1879 this->writeWord(fConstantZeroOneVector, fConstantBuffer);
1880 this->writeWord(zeroId, fConstantBuffer);
1881 this->writeWord(oneId, fConstantBuffer);
1882 }
1883 other = fConstantZeroOneVector;
1884 } else {
1885 other = base;
1886 }
1887 this->writeWord(other, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001888 for (int component : swizzle.fComponents) {
Ethan Nicholasac285b12019-02-12 16:05:18 -05001889 if (component == SKSL_SWIZZLE_0) {
Ethan Nicholas0b2c0542019-02-25 14:29:11 -05001890 this->writeWord(swizzle.fBase->fType.columns(), out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001891 } else if (component == SKSL_SWIZZLE_1) {
Ethan Nicholas0b2c0542019-02-25 14:29:11 -05001892 this->writeWord(swizzle.fBase->fType.columns() + 1, out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001893 } else {
1894 this->writeWord(component, out);
1895 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001896 }
1897 }
1898 return result;
1899}
1900
Greg Daniel64773e62016-11-22 09:44:03 -05001901SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1902 const Type& operandType, SpvId lhs,
1903 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001904 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001905 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001906 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001907 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001908 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001909 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001910 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001911 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001912 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001913 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001914 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07001915 } else {
1916 ABORT("invalid operandType: %s", operandType.description().c_str());
1917 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04001918 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001919 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
1920 fDecorationBuffer);
1921 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001922 return result;
1923}
1924
Ethan Nicholas48e24052018-03-14 13:51:39 -04001925SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
1926 OutputStream& out) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05001927 if (operandType.kind() == Type::kVector_Kind) {
1928 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001929 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05001930 return result;
1931 }
1932 return id;
1933}
1934
Ethan Nicholas68990be2017-07-13 09:36:52 -04001935SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
1936 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04001937 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04001938 OutputStream& out) {
1939 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001940 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0df21132018-07-10 09:37:51 -04001941 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
1942 operandType.rows(),
1943 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04001944 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04001945 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04001946 1));
1947 SpvId boolType = this->getType(*fContext.fBool_Type);
1948 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04001949 for (int i = 0; i < operandType.columns(); i++) {
1950 SpvId columnL = this->nextId();
1951 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
1952 SpvId columnR = this->nextId();
1953 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04001954 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04001955 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
1956 SpvId merge = this->nextId();
1957 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04001958 if (result != 0) {
1959 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04001960 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04001961 result = next;
1962 }
1963 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04001964 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04001965 }
1966 }
1967 return result;
1968}
1969
Ethan Nicholas0df21132018-07-10 09:37:51 -04001970SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
1971 SpvId rhs, SpvOp_ floatOperator,
1972 SpvOp_ intOperator,
1973 OutputStream& out) {
1974 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
1975 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
1976 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
1977 operandType.rows(),
1978 1));
1979 SpvId columns[4];
1980 for (int i = 0; i < operandType.columns(); i++) {
1981 SpvId columnL = this->nextId();
1982 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
1983 SpvId columnR = this->nextId();
1984 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
1985 columns[i] = this->nextId();
1986 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
1987 }
1988 SpvId result = this->nextId();
1989 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
1990 this->writeWord(this->getType(operandType), out);
1991 this->writeWord(result, out);
1992 for (int i = 0; i < operandType.columns(); i++) {
1993 this->writeWord(columns[i], out);
1994 }
1995 return result;
1996}
1997
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001998SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001999 // handle cases where we don't necessarily evaluate both LHS and RHS
2000 switch (b.fOperator) {
2001 case Token::EQ: {
2002 SpvId rhs = this->writeExpression(*b.fRight, out);
2003 this->getLValue(*b.fLeft, out)->store(rhs, out);
2004 return rhs;
2005 }
2006 case Token::LOGICALAND:
2007 return this->writeLogicalAnd(b, out);
2008 case Token::LOGICALOR:
2009 return this->writeLogicalOr(b, out);
2010 default:
2011 break;
2012 }
2013
2014 // "normal" operators
ethannicholasd598f792016-07-25 10:08:54 -07002015 const Type& resultType = b.fType;
ethannicholasb3058bd2016-07-01 08:22:01 -07002016 std::unique_ptr<LValue> lvalue;
2017 SpvId lhs;
2018 if (is_assignment(b.fOperator)) {
2019 lvalue = this->getLValue(*b.fLeft, out);
2020 lhs = lvalue->load(out);
2021 } else {
2022 lvalue = nullptr;
2023 lhs = this->writeExpression(*b.fLeft, out);
2024 }
2025 SpvId rhs = this->writeExpression(*b.fRight, out);
Ethan Nicholas6feb6912017-06-30 12:23:36 -04002026 if (b.fOperator == Token::COMMA) {
2027 return rhs;
2028 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002029 Type tmp("<invalid>");
Ethan Nicholas48e24052018-03-14 13:51:39 -04002030 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002031 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002032 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2033 // handling in SPIR-V
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002034 if (this->getActualType(b.fLeft->fType) != this->getActualType(b.fRight->fType)) {
Greg Daniel64773e62016-11-22 09:44:03 -05002035 if (b.fLeft->fType.kind() == Type::kVector_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002036 b.fRight->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002037 // promote number to vector
2038 SpvId vec = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04002039 const Type& vecType = b.fLeft->fType;
2040 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2041 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002042 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002043 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002044 this->writeWord(rhs, out);
2045 }
2046 rhs = vec;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002047 operandType = &b.fLeft->fType;
Greg Daniel64773e62016-11-22 09:44:03 -05002048 } else if (b.fRight->fType.kind() == Type::kVector_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002049 b.fLeft->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002050 // promote number to vector
2051 SpvId vec = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04002052 const Type& vecType = b.fRight->fType;
2053 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2054 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002055 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002056 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002057 this->writeWord(lhs, out);
2058 }
2059 lhs = vec;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002060 SkASSERT(!lvalue);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002061 operandType = &b.fRight->fType;
ethannicholasd598f792016-07-25 10:08:54 -07002062 } else if (b.fLeft->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002063 SpvOp_ op;
ethannicholasd598f792016-07-25 10:08:54 -07002064 if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002065 op = SpvOpMatrixTimesMatrix;
ethannicholasd598f792016-07-25 10:08:54 -07002066 } else if (b.fRight->fType.kind() == Type::kVector_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002067 op = SpvOpMatrixTimesVector;
2068 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002069 SkASSERT(b.fRight->fType.kind() == Type::kScalar_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07002070 op = SpvOpMatrixTimesScalar;
2071 }
2072 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002073 this->writeInstruction(op, this->getType(b.fType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002074 if (b.fOperator == Token::STAREQ) {
2075 lvalue->store(result, out);
2076 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002077 SkASSERT(b.fOperator == Token::STAR);
ethannicholasb3058bd2016-07-01 08:22:01 -07002078 }
2079 return result;
ethannicholasd598f792016-07-25 10:08:54 -07002080 } else if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002081 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002082 if (b.fLeft->fType.kind() == Type::kVector_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05002083 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(b.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002084 lhs, rhs, out);
2085 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002086 SkASSERT(b.fLeft->fType.kind() == Type::kScalar_Kind);
Greg Daniel64773e62016-11-22 09:44:03 -05002087 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(b.fType), result, rhs,
ethannicholasb3058bd2016-07-01 08:22:01 -07002088 lhs, out);
2089 }
2090 if (b.fOperator == Token::STAREQ) {
2091 lvalue->store(result, out);
2092 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002093 SkASSERT(b.fOperator == Token::STAR);
ethannicholasb3058bd2016-07-01 08:22:01 -07002094 }
2095 return result;
2096 } else {
Ethan Nicholase1f55022019-02-05 17:17:40 -05002097 ABORT("unsupported binary expression: %s (%s, %s)", b.description().c_str(),
2098 b.fLeft->fType.description().c_str(), b.fRight->fType.description().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002099 }
2100 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002101 tmp = this->getActualType(b.fLeft->fType);
2102 operandType = &tmp;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002103 SkASSERT(*operandType == this->getActualType(b.fRight->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002104 }
2105 switch (b.fOperator) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002106 case Token::EQEQ: {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002107 if (operandType->kind() == Type::kMatrix_Kind) {
2108 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002109 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002110 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002111 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002112 const Type* tmpType;
2113 if (operandType->kind() == Type::kVector_Kind) {
2114 tmpType = &fContext.fBool_Type->toCompound(fContext,
2115 operandType->columns(),
2116 operandType->rows());
2117 } else {
2118 tmpType = &resultType;
2119 }
2120 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002121 SpvOpFOrdEqual, SpvOpIEqual,
2122 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002123 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002124 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002125 case Token::NEQ:
Ethan Nicholas68990be2017-07-13 09:36:52 -04002126 if (operandType->kind() == Type::kMatrix_Kind) {
2127 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002128 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002129 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002130 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002131 const Type* tmpType;
2132 if (operandType->kind() == Type::kVector_Kind) {
2133 tmpType = &fContext.fBool_Type->toCompound(fContext,
2134 operandType->columns(),
2135 operandType->rows());
2136 } else {
2137 tmpType = &resultType;
2138 }
2139 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002140 SpvOpFOrdNotEqual, SpvOpINotEqual,
2141 SpvOpINotEqual, SpvOpLogicalNotEqual,
2142 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002143 *operandType, SpvOpAny, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002144 case Token::GT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002145 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002146 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2147 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002148 SpvOpUGreaterThan, SpvOpUndef, out);
2149 case Token::LT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002150 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002151 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002152 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
2153 case Token::GTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002154 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002155 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2156 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002157 SpvOpUGreaterThanEqual, SpvOpUndef, out);
2158 case Token::LTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002159 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002160 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2161 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002162 SpvOpULessThanEqual, SpvOpUndef, out);
2163 case Token::PLUS:
Ethan Nicholas0df21132018-07-10 09:37:51 -04002164 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2165 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2166 SkASSERT(b.fLeft->fType == b.fRight->fType);
2167 return this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2168 SpvOpFAdd, SpvOpIAdd, out);
2169 }
Greg Daniel64773e62016-11-22 09:44:03 -05002170 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002171 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2172 case Token::MINUS:
Ethan Nicholas0df21132018-07-10 09:37:51 -04002173 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2174 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2175 SkASSERT(b.fLeft->fType == b.fRight->fType);
2176 return this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2177 SpvOpFSub, SpvOpISub, out);
2178 }
Greg Daniel64773e62016-11-22 09:44:03 -05002179 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002180 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2181 case Token::STAR:
Greg Daniel64773e62016-11-22 09:44:03 -05002182 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002183 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002184 // matrix multiply
2185 SpvId result = this->nextId();
2186 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2187 lhs, rhs, out);
2188 return result;
2189 }
Greg Daniel64773e62016-11-22 09:44:03 -05002190 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002191 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2192 case Token::SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002193 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002194 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002195 case Token::PERCENT:
2196 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2197 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002198 case Token::SHL:
2199 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2200 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2201 SpvOpUndef, out);
2202 case Token::SHR:
2203 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2204 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2205 SpvOpUndef, out);
2206 case Token::BITWISEAND:
2207 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2208 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
2209 case Token::BITWISEOR:
2210 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2211 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
2212 case Token::BITWISEXOR:
2213 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2214 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002215 case Token::PLUSEQ: {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002216 SpvId result;
2217 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2218 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2219 SkASSERT(b.fLeft->fType == b.fRight->fType);
2220 result = this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2221 SpvOpFAdd, SpvOpIAdd, out);
2222 }
2223 else {
2224 result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002225 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002226 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002227 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002228 lvalue->store(result, out);
2229 return result;
2230 }
2231 case Token::MINUSEQ: {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002232 SpvId result;
2233 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2234 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2235 SkASSERT(b.fLeft->fType == b.fRight->fType);
2236 result = this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2237 SpvOpFSub, SpvOpISub, out);
2238 }
2239 else {
2240 result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002241 SpvOpISub, SpvOpISub, SpvOpUndef, out);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002242 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002243 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002244 lvalue->store(result, out);
2245 return result;
2246 }
2247 case Token::STAREQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002248 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002249 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002250 // matrix multiply
2251 SpvId result = this->nextId();
2252 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2253 lhs, rhs, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002254 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002255 lvalue->store(result, out);
2256 return result;
2257 }
Greg Daniel64773e62016-11-22 09:44:03 -05002258 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002259 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002260 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002261 lvalue->store(result, out);
2262 return result;
2263 }
2264 case Token::SLASHEQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002265 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002266 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002267 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002268 lvalue->store(result, out);
2269 return result;
2270 }
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002271 case Token::PERCENTEQ: {
2272 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2273 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002274 SkASSERT(lvalue);
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002275 lvalue->store(result, out);
2276 return result;
2277 }
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002278 case Token::SHLEQ: {
2279 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2280 SpvOpUndef, SpvOpShiftLeftLogical,
2281 SpvOpShiftLeftLogical, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002282 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002283 lvalue->store(result, out);
2284 return result;
2285 }
2286 case Token::SHREQ: {
2287 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2288 SpvOpUndef, SpvOpShiftRightArithmetic,
2289 SpvOpShiftRightLogical, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002290 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002291 lvalue->store(result, out);
2292 return result;
2293 }
2294 case Token::BITWISEANDEQ: {
2295 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2296 SpvOpUndef, SpvOpBitwiseAnd, SpvOpBitwiseAnd,
2297 SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002298 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002299 lvalue->store(result, out);
2300 return result;
2301 }
2302 case Token::BITWISEOREQ: {
2303 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2304 SpvOpUndef, SpvOpBitwiseOr, SpvOpBitwiseOr,
2305 SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002306 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002307 lvalue->store(result, out);
2308 return result;
2309 }
2310 case Token::BITWISEXOREQ: {
2311 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2312 SpvOpUndef, SpvOpBitwiseXor, SpvOpBitwiseXor,
2313 SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002314 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002315 lvalue->store(result, out);
2316 return result;
2317 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002318 default:
ethannicholasb3058bd2016-07-01 08:22:01 -07002319 ABORT("unsupported binary expression: %s", b.description().c_str());
2320 }
2321}
2322
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002323SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002324 SkASSERT(a.fOperator == Token::LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002325 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002326 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2327 SpvId lhs = this->writeExpression(*a.fLeft, out);
2328 SpvId rhsLabel = this->nextId();
2329 SpvId end = this->nextId();
2330 SpvId lhsBlock = fCurrentBlock;
2331 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2332 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2333 this->writeLabel(rhsLabel, out);
2334 SpvId rhs = this->writeExpression(*a.fRight, out);
2335 SpvId rhsBlock = fCurrentBlock;
2336 this->writeInstruction(SpvOpBranch, end, out);
2337 this->writeLabel(end, out);
2338 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002339 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002340 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002341 return result;
2342}
2343
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002344SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002345 SkASSERT(o.fOperator == Token::LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002346 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002347 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2348 SpvId lhs = this->writeExpression(*o.fLeft, out);
2349 SpvId rhsLabel = this->nextId();
2350 SpvId end = this->nextId();
2351 SpvId lhsBlock = fCurrentBlock;
2352 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2353 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2354 this->writeLabel(rhsLabel, out);
2355 SpvId rhs = this->writeExpression(*o.fRight, out);
2356 SpvId rhsBlock = fCurrentBlock;
2357 this->writeInstruction(SpvOpBranch, end, out);
2358 this->writeLabel(end, out);
2359 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002360 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002361 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002362 return result;
2363}
2364
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002365SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002366 SpvId test = this->writeExpression(*t.fTest, out);
Ethan Nicholas0f21c232018-07-23 09:25:40 -04002367 if (t.fIfTrue->fType.columns() == 1 && t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002368 // both true and false are constants, can just use OpSelect
2369 SpvId result = this->nextId();
2370 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2371 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
Greg Daniel64773e62016-11-22 09:44:03 -05002372 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002373 out);
2374 return result;
2375 }
Greg Daniel64773e62016-11-22 09:44:03 -05002376 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002377 // Adreno. Switched to storing the result in a temp variable as glslang does.
2378 SpvId var = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002379 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002380 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002381 SpvId trueLabel = this->nextId();
2382 SpvId falseLabel = this->nextId();
2383 SpvId end = this->nextId();
2384 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2385 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2386 this->writeLabel(trueLabel, out);
2387 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2388 this->writeInstruction(SpvOpBranch, end, out);
2389 this->writeLabel(falseLabel, out);
2390 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2391 this->writeInstruction(SpvOpBranch, end, out);
2392 this->writeLabel(end, out);
2393 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002394 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002395 this->writePrecisionModifier(t.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002396 return result;
2397}
2398
ethannicholasd598f792016-07-25 10:08:54 -07002399std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
Ethan Nicholas024301a2017-11-10 13:49:18 -05002400 if (type.isInteger()) {
Ethan Nicholas00543112018-07-31 09:44:36 -04002401 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002402 }
Ethan Nicholas024301a2017-11-10 13:49:18 -05002403 else if (type.isFloat()) {
Ethan Nicholas00543112018-07-31 09:44:36 -04002404 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002405 } else {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002406 ABORT("math is unsupported on type '%s'", type.name().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002407 }
2408}
2409
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002410SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002411 if (p.fOperator == Token::MINUS) {
2412 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002413 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002414 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002415 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002416 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002417 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002418 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2419 } else {
2420 ABORT("unsupported prefix expression %s", p.description().c_str());
Brian Salomon23356442018-11-30 15:33:19 -05002421 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002422 this->writePrecisionModifier(p.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002423 return result;
2424 }
2425 switch (p.fOperator) {
2426 case Token::PLUS:
2427 return this->writeExpression(*p.fOperand, out);
2428 case Token::PLUSPLUS: {
2429 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002430 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002431 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2432 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002433 out);
2434 lv->store(result, out);
2435 return result;
2436 }
2437 case Token::MINUSMINUS: {
2438 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002439 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002440 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2441 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002442 out);
2443 lv->store(result, out);
2444 return result;
2445 }
ethannicholas5961bc92016-10-12 06:39:56 -07002446 case Token::LOGICALNOT: {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002447 SkASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002448 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002449 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002450 this->writeExpression(*p.fOperand, out), out);
2451 return result;
2452 }
ethannicholas5961bc92016-10-12 06:39:56 -07002453 case Token::BITWISENOT: {
2454 SpvId result = this->nextId();
2455 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2456 this->writeExpression(*p.fOperand, out), out);
2457 return result;
2458 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002459 default:
2460 ABORT("unsupported prefix expression: %s", p.description().c_str());
2461 }
2462}
2463
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002464SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002465 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2466 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002467 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002468 switch (p.fOperator) {
2469 case Token::PLUSPLUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002470 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002471 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2472 lv->store(temp, out);
2473 return result;
2474 }
2475 case Token::MINUSMINUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002476 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002477 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2478 lv->store(temp, out);
2479 return result;
2480 }
2481 default:
2482 ABORT("unsupported postfix expression %s", p.description().c_str());
2483 }
2484}
2485
ethannicholasf789b382016-08-03 12:43:36 -07002486SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002487 if (b.fValue) {
2488 if (fBoolTrue == 0) {
2489 fBoolTrue = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002490 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002491 fConstantBuffer);
2492 }
2493 return fBoolTrue;
2494 } else {
2495 if (fBoolFalse == 0) {
2496 fBoolFalse = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002497 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002498 fConstantBuffer);
2499 }
2500 return fBoolFalse;
2501 }
2502}
2503
ethannicholasf789b382016-08-03 12:43:36 -07002504SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholasd598f792016-07-25 10:08:54 -07002505 if (i.fType == *fContext.fInt_Type) {
Greg Daniel5155e092019-04-17 15:28:51 +00002506 auto entry = fIntConstants.find(i.fValue);
2507 if (entry == fIntConstants.end()) {
2508 SpvId result = this->nextId();
2509 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
2510 fConstantBuffer);
2511 fIntConstants[i.fValue] = result;
2512 return result;
2513 }
2514 return entry->second;
2515 } else {
2516 SkASSERT(i.fType == *fContext.fUInt_Type);
2517 auto entry = fUIntConstants.find(i.fValue);
2518 if (entry == fUIntConstants.end()) {
2519 SpvId result = this->nextId();
2520 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
2521 fConstantBuffer);
2522 fUIntConstants[i.fValue] = result;
2523 return result;
2524 }
2525 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002526 }
2527}
2528
ethannicholasf789b382016-08-03 12:43:36 -07002529SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholase1f55022019-02-05 17:17:40 -05002530 if (f.fType != *fContext.fDouble_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002531 float value = (float) f.fValue;
Greg Daniel5155e092019-04-17 15:28:51 +00002532 auto entry = fFloatConstants.find(value);
2533 if (entry == fFloatConstants.end()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002534 SpvId result = this->nextId();
2535 uint32_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002536 SkASSERT(sizeof(bits) == sizeof(value));
ethannicholasb3058bd2016-07-01 08:22:01 -07002537 memcpy(&bits, &value, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002538 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
ethannicholasb3058bd2016-07-01 08:22:01 -07002539 fConstantBuffer);
Greg Daniel5155e092019-04-17 15:28:51 +00002540 fFloatConstants[value] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002541 return result;
2542 }
2543 return entry->second;
2544 } else {
Greg Daniel5155e092019-04-17 15:28:51 +00002545 auto entry = fDoubleConstants.find(f.fValue);
2546 if (entry == fDoubleConstants.end()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002547 SpvId result = this->nextId();
2548 uint64_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002549 SkASSERT(sizeof(bits) == sizeof(f.fValue));
ethannicholasb3058bd2016-07-01 08:22:01 -07002550 memcpy(&bits, &f.fValue, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002551 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002552 bits & 0xffffffff, bits >> 32, fConstantBuffer);
Greg Daniel5155e092019-04-17 15:28:51 +00002553 fDoubleConstants[f.fValue] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002554 return result;
2555 }
2556 return entry->second;
2557 }
2558}
2559
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002560SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002561 SpvId result = fFunctionMap[&f];
Greg Daniel64773e62016-11-22 09:44:03 -05002562 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002563 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002564 this->writeInstruction(SpvOpName, result, f.fName, fNameBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002565 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002566 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002567 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002568 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002569 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002570 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2571 }
2572 return result;
2573}
2574
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002575SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2576 fVariableBuffer.reset();
ethannicholasb3058bd2016-07-01 08:22:01 -07002577 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2578 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002579 StringStream bodyBuffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04002580 this->writeBlock((Block&) *f.fBody, bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002581 write_stringstream(fVariableBuffer, out);
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002582 if (f.fDeclaration.fName == "main") {
2583 write_stringstream(fGlobalInitializersBuffer, out);
2584 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002585 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002586 if (fCurrentBlock) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002587 if (f.fDeclaration.fReturnType == *fContext.fVoid_Type) {
2588 this->writeInstruction(SpvOpReturn, out);
2589 } else {
2590 this->writeInstruction(SpvOpUnreachable, out);
2591 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002592 }
2593 this->writeInstruction(SpvOpFunctionEnd, out);
2594 return result;
2595}
2596
2597void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2598 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002599 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002600 fDecorationBuffer);
2601 }
2602 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002603 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002604 fDecorationBuffer);
2605 }
2606 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002607 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002608 fDecorationBuffer);
2609 }
2610 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002611 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002612 fDecorationBuffer);
2613 }
Greg Daniel64773e62016-11-22 09:44:03 -05002614 if (layout.fInputAttachmentIndex >= 0) {
2615 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2616 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002617 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002618 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002619 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002620 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002621 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002622 fDecorationBuffer);
2623 }
2624}
2625
2626void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2627 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002628 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002629 layout.fLocation, fDecorationBuffer);
2630 }
2631 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002632 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002633 layout.fBinding, fDecorationBuffer);
2634 }
2635 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002636 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002637 layout.fIndex, fDecorationBuffer);
2638 }
2639 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002640 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002641 layout.fSet, fDecorationBuffer);
2642 }
Greg Daniel64773e62016-11-22 09:44:03 -05002643 if (layout.fInputAttachmentIndex >= 0) {
2644 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2645 layout.fInputAttachmentIndex, fDecorationBuffer);
2646 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002647 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002648 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002649 layout.fBuiltin, fDecorationBuffer);
2650 }
2651}
2652
Ethan Nicholas81d15112018-07-13 12:48:50 -04002653static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2654 switch (m.fLayout.fPrimitive) {
2655 case Layout::kPoints_Primitive:
2656 *outSkInCount = 1;
2657 break;
2658 case Layout::kLines_Primitive:
2659 *outSkInCount = 2;
2660 break;
2661 case Layout::kLinesAdjacency_Primitive:
2662 *outSkInCount = 4;
2663 break;
2664 case Layout::kTriangles_Primitive:
2665 *outSkInCount = 3;
2666 break;
2667 case Layout::kTrianglesAdjacency_Primitive:
2668 *outSkInCount = 6;
2669 break;
2670 default:
2671 return;
2672 }
2673}
2674
ethannicholasf789b382016-08-03 12:43:36 -07002675SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas361941e2017-05-30 15:41:07 -04002676 bool isBuffer = (0 != (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag));
Ethan Nicholas39204fd2017-11-27 13:12:30 -05002677 bool pushConstant = (0 != (intf.fVariable.fModifiers.fLayout.fFlags &
2678 Layout::kPushConstant_Flag));
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002679 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2680 MemoryLayout(MemoryLayout::k430_Standard) :
2681 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002682 SpvId result = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002683 const Type* type = &intf.fVariable.fType;
Greg Daniele6ab9982018-08-22 13:56:32 +00002684 if (fProgram.fInputs.fRTHeight) {
2685 SkASSERT(fRTHeightStructId == (SpvId) -1);
2686 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002687 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002688 fRTHeightStructId = result;
2689 fRTHeightFieldIndex = fields.size();
2690 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002691 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002692 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002693 SpvId typeId;
2694 if (intf.fVariable.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2695 for (const auto& e : fProgram) {
2696 if (e.fKind == ProgramElement::kModifiers_Kind) {
2697 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholas81d15112018-07-13 12:48:50 -04002698 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002699 }
2700 }
2701 typeId = this->getType(Type("sk_in", Type::kArray_Kind, intf.fVariable.fType.componentType(),
2702 fSkInCount), memoryLayout);
2703 } else {
2704 typeId = this->getType(*type, memoryLayout);
2705 }
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002706 if (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag) {
2707 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002708 } else if (intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
2709 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002710 }
ethannicholasd598f792016-07-25 10:08:54 -07002711 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002712 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002713 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002714 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002715 Layout layout = intf.fVariable.fModifiers.fLayout;
2716 if (intf.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
2717 layout.fSet = 0;
2718 }
2719 this->writeLayout(layout, result);
ethannicholasd598f792016-07-25 10:08:54 -07002720 fVariableMap[&intf.fVariable] = result;
Greg Daniele6ab9982018-08-22 13:56:32 +00002721 if (fProgram.fInputs.fRTHeight) {
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002722 delete type;
2723 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002724 return result;
2725}
2726
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002727void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002728 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2729}
2730
2731void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2732 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002733 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2734 }
2735}
2736
ethannicholas5961bc92016-10-12 06:39:56 -07002737#define BUILTIN_IGNORE 9999
Greg Daniel64773e62016-11-22 09:44:03 -05002738void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002739 OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002740 for (size_t i = 0; i < decl.fVars.size(); i++) {
2741 if (decl.fVars[i]->fKind == Statement::kNop_Kind) {
2742 continue;
2743 }
2744 const VarDeclaration& varDecl = (VarDeclaration&) *decl.fVars[i];
2745 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002746 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2747 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002748 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002749 Modifiers::kWriteOnly_Flag |
2750 Modifiers::kCoherent_Flag |
2751 Modifiers::kVolatile_Flag |
2752 Modifiers::kRestrict_Flag)));
ethannicholas5961bc92016-10-12 06:39:56 -07002753 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2754 continue;
2755 }
2756 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2757 kind != Program::kFragment_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002758 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
ethannicholas5961bc92016-10-12 06:39:56 -07002759 continue;
2760 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05002761 if (!var->fReadCount && !var->fWriteCount &&
ethannicholas14fe8cc2016-09-07 13:37:16 -07002762 !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
2763 Modifiers::kOut_Flag |
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002764 Modifiers::kUniform_Flag |
2765 Modifiers::kBuffer_Flag))) {
ethannicholasd598f792016-07-25 10:08:54 -07002766 // variable is dead and not an input / output var (the Vulkan debug layers complain if
2767 // we elide an interface var, even if it's dead)
ethannicholasb3058bd2016-07-01 08:22:01 -07002768 continue;
2769 }
2770 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002771 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002772 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002773 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002774 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002775 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
2776 if (var->fType.kind() == Type::kSampler_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002777 storageClass = SpvStorageClassUniformConstant;
2778 } else {
2779 storageClass = SpvStorageClassUniform;
2780 }
2781 } else {
2782 storageClass = SpvStorageClassPrivate;
2783 }
2784 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002785 fVariableMap[var] = id;
Ethan Nicholas5226b772018-05-03 16:20:41 -04002786 SpvId type;
2787 if (var->fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2788 type = this->getPointerType(Type("sk_in", Type::kArray_Kind,
2789 var->fType.componentType(), fSkInCount),
2790 storageClass);
2791 } else {
2792 type = this->getPointerType(var->fType, storageClass);
2793 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002794 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002795 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002796 this->writePrecisionModifier(var->fType, id);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002797 if (varDecl.fValue) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002798 SkASSERT(!fCurrentBlock);
ethannicholasf789b382016-08-03 12:43:36 -07002799 fCurrentBlock = -1;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002800 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002801 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002802 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002803 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002804 this->writeLayout(var->fModifiers.fLayout, id);
Ethan Nicholas45b0f152017-07-24 14:36:40 -04002805 if (var->fModifiers.fFlags & Modifiers::kFlat_Flag) {
2806 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2807 }
2808 if (var->fModifiers.fFlags & Modifiers::kNoPerspective_Flag) {
2809 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2810 fDecorationBuffer);
2811 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002812 }
2813}
2814
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002815void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002816 for (const auto& stmt : decl.fVars) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002817 SkASSERT(stmt->fKind == Statement::kVarDeclaration_Kind);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002818 VarDeclaration& varDecl = (VarDeclaration&) *stmt;
2819 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002820 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2821 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002822 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002823 Modifiers::kWriteOnly_Flag |
2824 Modifiers::kCoherent_Flag |
2825 Modifiers::kVolatile_Flag |
2826 Modifiers::kRestrict_Flag)));
ethannicholasb3058bd2016-07-01 08:22:01 -07002827 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002828 fVariableMap[var] = id;
2829 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002830 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002831 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002832 if (varDecl.fValue) {
2833 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002834 this->writeInstruction(SpvOpStore, id, value, out);
2835 }
2836 }
2837}
2838
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002839void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002840 switch (s.fKind) {
Ethan Nicholascb670962017-04-20 19:31:52 -04002841 case Statement::kNop_Kind:
2842 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002843 case Statement::kBlock_Kind:
2844 this->writeBlock((Block&) s, out);
2845 break;
2846 case Statement::kExpression_Kind:
2847 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2848 break;
Greg Daniel64773e62016-11-22 09:44:03 -05002849 case Statement::kReturn_Kind:
ethannicholasb3058bd2016-07-01 08:22:01 -07002850 this->writeReturnStatement((ReturnStatement&) s, out);
2851 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002852 case Statement::kVarDeclarations_Kind:
2853 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002854 break;
2855 case Statement::kIf_Kind:
2856 this->writeIfStatement((IfStatement&) s, out);
2857 break;
2858 case Statement::kFor_Kind:
2859 this->writeForStatement((ForStatement&) s, out);
2860 break;
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002861 case Statement::kWhile_Kind:
2862 this->writeWhileStatement((WhileStatement&) s, out);
2863 break;
2864 case Statement::kDo_Kind:
2865 this->writeDoStatement((DoStatement&) s, out);
2866 break;
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002867 case Statement::kSwitch_Kind:
2868 this->writeSwitchStatement((SwitchStatement&) s, out);
2869 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002870 case Statement::kBreak_Kind:
2871 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2872 break;
2873 case Statement::kContinue_Kind:
2874 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2875 break;
2876 case Statement::kDiscard_Kind:
2877 this->writeInstruction(SpvOpKill, out);
2878 break;
2879 default:
2880 ABORT("unsupported statement: %s", s.description().c_str());
2881 }
2882}
2883
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002884void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002885 for (size_t i = 0; i < b.fStatements.size(); i++) {
2886 this->writeStatement(*b.fStatements[i], out);
2887 }
2888}
2889
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002890void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002891 SpvId test = this->writeExpression(*stmt.fTest, out);
2892 SpvId ifTrue = this->nextId();
2893 SpvId ifFalse = this->nextId();
2894 if (stmt.fIfFalse) {
2895 SpvId end = this->nextId();
2896 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2897 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2898 this->writeLabel(ifTrue, out);
2899 this->writeStatement(*stmt.fIfTrue, out);
2900 if (fCurrentBlock) {
2901 this->writeInstruction(SpvOpBranch, end, out);
2902 }
2903 this->writeLabel(ifFalse, out);
2904 this->writeStatement(*stmt.fIfFalse, out);
2905 if (fCurrentBlock) {
2906 this->writeInstruction(SpvOpBranch, end, out);
2907 }
2908 this->writeLabel(end, out);
2909 } else {
2910 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2911 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2912 this->writeLabel(ifTrue, out);
2913 this->writeStatement(*stmt.fIfTrue, out);
2914 if (fCurrentBlock) {
2915 this->writeInstruction(SpvOpBranch, ifFalse, out);
2916 }
2917 this->writeLabel(ifFalse, out);
2918 }
2919}
2920
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002921void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002922 if (f.fInitializer) {
2923 this->writeStatement(*f.fInitializer, out);
2924 }
2925 SpvId header = this->nextId();
2926 SpvId start = this->nextId();
2927 SpvId body = this->nextId();
2928 SpvId next = this->nextId();
2929 fContinueTarget.push(next);
2930 SpvId end = this->nextId();
2931 fBreakTarget.push(end);
2932 this->writeInstruction(SpvOpBranch, header, out);
2933 this->writeLabel(header, out);
2934 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002935 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002936 this->writeLabel(start, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002937 if (f.fTest) {
2938 SpvId test = this->writeExpression(*f.fTest, out);
2939 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2940 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002941 this->writeLabel(body, out);
2942 this->writeStatement(*f.fStatement, out);
2943 if (fCurrentBlock) {
2944 this->writeInstruction(SpvOpBranch, next, out);
2945 }
2946 this->writeLabel(next, out);
2947 if (f.fNext) {
2948 this->writeExpression(*f.fNext, out);
2949 }
2950 this->writeInstruction(SpvOpBranch, header, out);
2951 this->writeLabel(end, out);
2952 fBreakTarget.pop();
2953 fContinueTarget.pop();
2954}
2955
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002956void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002957 SpvId header = this->nextId();
2958 SpvId start = this->nextId();
2959 SpvId body = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04002960 SpvId continueTarget = this->nextId();
2961 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002962 SpvId end = this->nextId();
2963 fBreakTarget.push(end);
2964 this->writeInstruction(SpvOpBranch, header, out);
2965 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04002966 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002967 this->writeInstruction(SpvOpBranch, start, out);
2968 this->writeLabel(start, out);
2969 SpvId test = this->writeExpression(*w.fTest, out);
2970 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2971 this->writeLabel(body, out);
2972 this->writeStatement(*w.fStatement, out);
2973 if (fCurrentBlock) {
Ethan Nicholas0d997662019-04-08 09:46:01 -04002974 this->writeInstruction(SpvOpBranch, continueTarget, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002975 }
Ethan Nicholas0d997662019-04-08 09:46:01 -04002976 this->writeLabel(continueTarget, out);
2977 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002978 this->writeLabel(end, out);
2979 fBreakTarget.pop();
2980 fContinueTarget.pop();
2981}
2982
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002983void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002984 // We believe the do loop code below will work, but Skia doesn't actually use them and
2985 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2986 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2987 // message, simply remove the error call below to see whether our do loop support actually
2988 // works.
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002989 fErrors.error(d.fOffset, "internal error: do loop support has been disabled in SPIR-V, see "
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002990 "SkSLSPIRVCodeGenerator.cpp for details");
2991
2992 SpvId header = this->nextId();
2993 SpvId start = this->nextId();
2994 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04002995 SpvId continueTarget = this->nextId();
2996 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002997 SpvId end = this->nextId();
2998 fBreakTarget.push(end);
2999 this->writeInstruction(SpvOpBranch, header, out);
3000 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003001 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003002 this->writeInstruction(SpvOpBranch, start, out);
3003 this->writeLabel(start, out);
3004 this->writeStatement(*d.fStatement, out);
3005 if (fCurrentBlock) {
3006 this->writeInstruction(SpvOpBranch, next, out);
3007 }
3008 this->writeLabel(next, out);
3009 SpvId test = this->writeExpression(*d.fTest, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003010 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
3011 this->writeLabel(continueTarget, out);
3012 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003013 this->writeLabel(end, out);
3014 fBreakTarget.pop();
3015 fContinueTarget.pop();
3016}
3017
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003018void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
3019 SpvId value = this->writeExpression(*s.fValue, out);
3020 std::vector<SpvId> labels;
3021 SpvId end = this->nextId();
3022 SpvId defaultLabel = end;
3023 fBreakTarget.push(end);
3024 int size = 3;
3025 for (const auto& c : s.fCases) {
3026 SpvId label = this->nextId();
3027 labels.push_back(label);
3028 if (c->fValue) {
3029 size += 2;
3030 } else {
3031 defaultLabel = label;
3032 }
3033 }
3034 labels.push_back(end);
3035 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3036 this->writeOpCode(SpvOpSwitch, size, out);
3037 this->writeWord(value, out);
3038 this->writeWord(defaultLabel, out);
3039 for (size_t i = 0; i < s.fCases.size(); ++i) {
3040 if (!s.fCases[i]->fValue) {
3041 continue;
3042 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003043 SkASSERT(s.fCases[i]->fValue->fKind == Expression::kIntLiteral_Kind);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003044 this->writeWord(((IntLiteral&) *s.fCases[i]->fValue).fValue, out);
3045 this->writeWord(labels[i], out);
3046 }
3047 for (size_t i = 0; i < s.fCases.size(); ++i) {
3048 this->writeLabel(labels[i], out);
3049 for (const auto& stmt : s.fCases[i]->fStatements) {
3050 this->writeStatement(*stmt, out);
3051 }
3052 if (fCurrentBlock) {
3053 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3054 }
3055 }
3056 this->writeLabel(end, out);
3057 fBreakTarget.pop();
3058}
3059
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003060void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003061 if (r.fExpression) {
Greg Daniel64773e62016-11-22 09:44:03 -05003062 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003063 out);
3064 } else {
3065 this->writeInstruction(SpvOpReturn, out);
3066 }
3067}
3068
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003069void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003070 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003071 int invocations = 1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003072 for (const auto& e : fProgram) {
3073 if (e.fKind == ProgramElement::kModifiers_Kind) {
3074 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003075 if (m.fFlags & Modifiers::kIn_Flag) {
3076 if (m.fLayout.fInvocations != -1) {
3077 invocations = m.fLayout.fInvocations;
3078 }
3079 SpvId input;
3080 switch (m.fLayout.fPrimitive) {
3081 case Layout::kPoints_Primitive:
3082 input = SpvExecutionModeInputPoints;
3083 break;
3084 case Layout::kLines_Primitive:
3085 input = SpvExecutionModeInputLines;
3086 break;
3087 case Layout::kLinesAdjacency_Primitive:
3088 input = SpvExecutionModeInputLinesAdjacency;
3089 break;
3090 case Layout::kTriangles_Primitive:
3091 input = SpvExecutionModeTriangles;
3092 break;
3093 case Layout::kTrianglesAdjacency_Primitive:
3094 input = SpvExecutionModeInputTrianglesAdjacency;
3095 break;
3096 default:
3097 input = 0;
3098 break;
3099 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003100 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003101 if (input) {
3102 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3103 }
3104 } else if (m.fFlags & Modifiers::kOut_Flag) {
3105 SpvId output;
3106 switch (m.fLayout.fPrimitive) {
3107 case Layout::kPoints_Primitive:
3108 output = SpvExecutionModeOutputPoints;
3109 break;
3110 case Layout::kLineStrip_Primitive:
3111 output = SpvExecutionModeOutputLineStrip;
3112 break;
3113 case Layout::kTriangleStrip_Primitive:
3114 output = SpvExecutionModeOutputTriangleStrip;
3115 break;
3116 default:
3117 output = 0;
3118 break;
3119 }
3120 if (output) {
3121 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3122 }
3123 if (m.fLayout.fMaxVertices != -1) {
3124 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3125 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3126 out);
3127 }
3128 }
3129 }
3130 }
3131 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3132 invocations, out);
3133}
3134
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003135void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003136 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003137 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003138 std::set<SpvId> interfaceVars;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003139 // assign IDs to functions, determine sk_in size
3140 int skInSize = -1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003141 for (const auto& e : program) {
3142 switch (e.fKind) {
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003143 case ProgramElement::kFunction_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003144 FunctionDefinition& f = (FunctionDefinition&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003145 fFunctionMap[&f.fDeclaration] = this->nextId();
3146 break;
3147 }
3148 case ProgramElement::kModifiers_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003149 Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003150 if (m.fFlags & Modifiers::kIn_Flag) {
3151 switch (m.fLayout.fPrimitive) {
3152 case Layout::kPoints_Primitive: // break
3153 case Layout::kLines_Primitive:
3154 skInSize = 1;
3155 break;
3156 case Layout::kLinesAdjacency_Primitive: // break
3157 skInSize = 2;
3158 break;
3159 case Layout::kTriangles_Primitive: // break
3160 case Layout::kTrianglesAdjacency_Primitive:
3161 skInSize = 3;
3162 break;
3163 default:
3164 break;
3165 }
3166 }
3167 break;
3168 }
3169 default:
3170 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003171 }
3172 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003173 for (const auto& e : program) {
3174 if (e.fKind == ProgramElement::kInterfaceBlock_Kind) {
3175 InterfaceBlock& intf = (InterfaceBlock&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003176 if (SK_IN_BUILTIN == intf.fVariable.fModifiers.fLayout.fBuiltin) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003177 SkASSERT(skInSize != -1);
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003178 intf.fSizes.emplace_back(new IntLiteral(fContext, -1, skInSize));
3179 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003180 SpvId id = this->writeInterfaceBlock(intf);
Ethan Nicholas16c11962018-03-16 12:20:54 -04003181 if (((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
3182 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) &&
3183 intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003184 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003185 }
3186 }
3187 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003188 for (const auto& e : program) {
3189 if (e.fKind == ProgramElement::kVar_Kind) {
3190 this->writeGlobalVars(program.fKind, ((VarDeclarations&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003191 }
3192 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003193 for (const auto& e : program) {
3194 if (e.fKind == ProgramElement::kFunction_Kind) {
3195 this->writeFunction(((FunctionDefinition&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003196 }
3197 }
ethannicholasd598f792016-07-25 10:08:54 -07003198 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003199 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07003200 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003201 main = entry.first;
3202 }
3203 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003204 SkASSERT(main);
ethannicholasb3058bd2016-07-01 08:22:01 -07003205 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003206 const Variable* var = entry.first;
Greg Daniel64773e62016-11-22 09:44:03 -05003207 if (var->fStorage == Variable::kGlobal_Storage &&
Ethan Nicholas16c11962018-03-16 12:20:54 -04003208 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
Ethan Nicholasd23c8192018-09-26 17:01:24 -04003209 (var->fModifiers.fFlags & Modifiers::kOut_Flag))) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003210 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003211 }
3212 }
3213 this->writeCapabilities(out);
3214 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3215 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003216 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->fName.fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003217 (int32_t) interfaceVars.size(), out);
3218 switch (program.fKind) {
3219 case Program::kVertex_Kind:
3220 this->writeWord(SpvExecutionModelVertex, out);
3221 break;
3222 case Program::kFragment_Kind:
3223 this->writeWord(SpvExecutionModelFragment, out);
3224 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003225 case Program::kGeometry_Kind:
3226 this->writeWord(SpvExecutionModelGeometry, out);
3227 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003228 default:
3229 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003230 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003231 SpvId entryPoint = fFunctionMap[main];
3232 this->writeWord(entryPoint, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003233 this->writeString(main->fName.fChars, main->fName.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003234 for (int var : interfaceVars) {
3235 this->writeWord(var, out);
3236 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003237 if (program.fKind == Program::kGeometry_Kind) {
3238 this->writeGeometryShaderExecutionMode(entryPoint, out);
3239 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003240 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003241 this->writeInstruction(SpvOpExecutionMode,
3242 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003243 SpvExecutionModeOriginUpperLeft,
3244 out);
3245 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003246 for (const auto& e : program) {
3247 if (e.fKind == ProgramElement::kExtension_Kind) {
3248 this->writeInstruction(SpvOpSourceExtension, ((Extension&) e).fName.c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003249 }
3250 }
Greg Daniel64773e62016-11-22 09:44:03 -05003251
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003252 write_stringstream(fExtraGlobalsBuffer, out);
3253 write_stringstream(fNameBuffer, out);
3254 write_stringstream(fDecorationBuffer, out);
3255 write_stringstream(fConstantBuffer, out);
3256 write_stringstream(fExternalFunctionsBuffer, out);
3257 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003258}
3259
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003260bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003261 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003262 this->writeWord(SpvMagicNumber, *fOut);
3263 this->writeWord(SpvVersion, *fOut);
3264 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003265 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003266 this->writeInstructions(fProgram, buffer);
3267 this->writeWord(fIdCount, *fOut);
3268 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003269 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003270 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003271}
3272
3273}