blob: 3357faaa6ef7beeaf708c85583ba21e0524fa308 [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 Nicholas0df1b042017-03-31 13:56:23 -040072 fIntrinsicMap[String("dot")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
Ethan Nicholas0187ae62017-05-03 11:03:44 -040073 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050074 fIntrinsicMap[String("mix")] = SPECIAL(Mix);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040075 fIntrinsicMap[String("step")] = ALL_GLSL(Step);
76 fIntrinsicMap[String("smoothstep")] = ALL_GLSL(SmoothStep);
77 fIntrinsicMap[String("fma")] = ALL_GLSL(Fma);
78 fIntrinsicMap[String("frexp")] = ALL_GLSL(Frexp);
79 fIntrinsicMap[String("ldexp")] = ALL_GLSL(Ldexp);
ethannicholasb3058bd2016-07-01 08:22:01 -070080
Ethan Nicholas0df1b042017-03-31 13:56:23 -040081#define PACK(type) fIntrinsicMap[String("pack" #type)] = ALL_GLSL(Pack ## type); \
82 fIntrinsicMap[String("unpack" #type)] = ALL_GLSL(Unpack ## type)
ethannicholasb3058bd2016-07-01 08:22:01 -070083 PACK(Snorm4x8);
84 PACK(Unorm4x8);
85 PACK(Snorm2x16);
86 PACK(Unorm2x16);
87 PACK(Half2x16);
88 PACK(Double2x32);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040089 fIntrinsicMap[String("length")] = ALL_GLSL(Length);
90 fIntrinsicMap[String("distance")] = ALL_GLSL(Distance);
91 fIntrinsicMap[String("cross")] = ALL_GLSL(Cross);
92 fIntrinsicMap[String("normalize")] = ALL_GLSL(Normalize);
93 fIntrinsicMap[String("faceForward")] = ALL_GLSL(FaceForward);
94 fIntrinsicMap[String("reflect")] = ALL_GLSL(Reflect);
95 fIntrinsicMap[String("refract")] = ALL_GLSL(Refract);
96 fIntrinsicMap[String("findLSB")] = ALL_GLSL(FindILsb);
97 fIntrinsicMap[String("findMSB")] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
98 fIntrinsicMap[String("dFdx")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
Ethan Nicholas0187ae62017-05-03 11:03:44 -040099 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400100 fIntrinsicMap[String("dFdy")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400101 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400102 fIntrinsicMap[String("dFdy")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy,
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++) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500392 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;
395 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,
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500398 "offset of field '" + type.fields()[i].fName + "' must be at "
399 "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,
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500403 "offset of field '" + type.fields()[i].fName + "' must be a multiple"
404 " 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 }
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700413 this->writeInstruction(SpvOpMemberName, resultId, i, type.fields()[i].fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500414 this->writeLayout(fieldLayout, resultId, i);
ethannicholasb3058bd2016-07-01 08:22:01 -0700415 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 }
ethannicholas0730be72016-09-01 07:59:02 -0700419 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,
Ethan Nicholas19671772016-11-28 16:30:17 -0500423 (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;
ethannicholas0730be72016-09-01 07:59:02 -0700427 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) {
435 if (type == *fContext.fHalf_Type) {
436 return *fContext.fFloat_Type;
437 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400438 if (type == *fContext.fShort_Type || type == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400439 return *fContext.fInt_Type;
440 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400441 if (type == *fContext.fUShort_Type || type == *fContext.fUByte_Type) {
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);
ethannicholasd598f792016-07-25 10:08:54 -0700474 } else if (type == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700475 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -0700476 } else if (type == *fContext.fUInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700477 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -0700478 } else if (type == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700479 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -0700480 } else if (type == *fContext.fDouble_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700481 this->writeInstruction(SpvOpTypeFloat, result, 64, fConstantBuffer);
482 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400483 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700484 }
485 break;
486 case Type::kVector_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500487 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800488 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700489 type.columns(), fConstantBuffer);
490 break;
491 case Type::kMatrix_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500492 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800493 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700494 type.columns(), fConstantBuffer);
495 break;
496 case Type::kStruct_Kind:
ethannicholas8ac838d2016-11-22 08:39:36 -0800497 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700498 break;
499 case Type::kArray_Kind: {
500 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700501 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500502 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800503 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700504 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500505 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400506 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800507 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700508 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400509 SkASSERT(false); // we shouldn't have any runtime-sized arrays right now
Greg Daniel64773e62016-11-22 09:44:03 -0500510 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800511 this->getType(type.componentType(), layout),
512 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400513 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
514 (int32_t) layout.stride(type),
515 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700516 }
517 break;
518 }
519 case Type::kSampler_Kind: {
Greg Daniel64773e62016-11-22 09:44:03 -0500520 SpvId image = result;
521 if (SpvDimSubpassData != type.dimensions()) {
522 image = this->nextId();
523 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400524 if (SpvDimBuffer == type.dimensions()) {
525 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
526 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800527 this->writeInstruction(SpvOpTypeImage, image,
528 this->getType(*fContext.fFloat_Type, layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700529 type.dimensions(), type.isDepth(), type.isArrayed(),
Greg Daniel64773e62016-11-22 09:44:03 -0500530 type.isMultisampled(), type.isSampled() ? 1 : 2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700531 SpvImageFormatUnknown, fConstantBuffer);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400532 fImageTypeMap[key] = image;
Greg Daniel64773e62016-11-22 09:44:03 -0500533 if (SpvDimSubpassData != type.dimensions()) {
534 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
535 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700536 break;
537 }
538 default:
ethannicholasd598f792016-07-25 10:08:54 -0700539 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700540 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
541 } else {
542 ABORT("invalid type: %s", type.description().c_str());
543 }
544 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800545 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700546 return result;
547 }
548 return entry->second;
549}
550
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400551SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400552 SkASSERT(type.kind() == Type::kSampler_Kind);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400553 this->getType(type);
554 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400555 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400556 return fImageTypeMap[key];
557}
558
ethannicholasd598f792016-07-25 10:08:54 -0700559SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400560 String key = function.fReturnType.description() + "(";
561 String separator;
ethannicholasd598f792016-07-25 10:08:54 -0700562 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700563 key += separator;
564 separator = ", ";
ethannicholasd598f792016-07-25 10:08:54 -0700565 key += function.fParameters[i]->fType.description();
ethannicholasb3058bd2016-07-01 08:22:01 -0700566 }
567 key += ")";
568 auto entry = fTypeMap.find(key);
569 if (entry == fTypeMap.end()) {
570 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -0700571 int32_t length = 3 + (int32_t) function.fParameters.size();
572 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700573 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -0700574 for (size_t i = 0; i < function.fParameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500575 // glslang seems to treat all function arguments as pointers whether they need to be or
576 // not. I was initially puzzled by this until I ran bizarre failures with certain
577 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700578 // failure case:
579 //
580 // void sphere(float x) {
581 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500582 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700583 // void map() {
584 // sphere(1.0);
585 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500586 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700587 // void main() {
588 // for (int i = 0; i < 1; i++) {
589 // map();
590 // }
591 // }
592 //
Greg Daniel64773e62016-11-22 09:44:03 -0500593 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
594 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700595 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
596 // the spec makes this make sense.
597// if (is_out(function->fParameters[i])) {
ethannicholasd598f792016-07-25 10:08:54 -0700598 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -0700599 SpvStorageClassFunction));
600// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700601// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700602// }
603 }
604 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
605 this->writeWord(result, fConstantBuffer);
606 this->writeWord(returnType, fConstantBuffer);
607 for (SpvId id : parameterTypes) {
608 this->writeWord(id, fConstantBuffer);
609 }
610 fTypeMap[key] = result;
611 return result;
612 }
613 return entry->second;
614}
615
ethannicholas8ac838d2016-11-22 08:39:36 -0800616SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
617 return this->getPointerType(type, fDefaultLayout, storageClass);
618}
619
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400620SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700621 SpvStorageClass_ storageClass) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400622 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400623 String key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700624 auto entry = fTypeMap.find(key);
625 if (entry == fTypeMap.end()) {
626 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500627 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700628 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700629 fTypeMap[key] = result;
630 return result;
631 }
632 return entry->second;
633}
634
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400635SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700636 switch (expr.fKind) {
637 case Expression::kBinary_Kind:
638 return this->writeBinaryExpression((BinaryExpression&) expr, out);
639 case Expression::kBoolLiteral_Kind:
640 return this->writeBoolLiteral((BoolLiteral&) expr);
641 case Expression::kConstructor_Kind:
642 return this->writeConstructor((Constructor&) expr, out);
643 case Expression::kIntLiteral_Kind:
644 return this->writeIntLiteral((IntLiteral&) expr);
645 case Expression::kFieldAccess_Kind:
646 return this->writeFieldAccess(((FieldAccess&) expr), out);
647 case Expression::kFloatLiteral_Kind:
648 return this->writeFloatLiteral(((FloatLiteral&) expr));
649 case Expression::kFunctionCall_Kind:
650 return this->writeFunctionCall((FunctionCall&) expr, out);
651 case Expression::kPrefix_Kind:
652 return this->writePrefixExpression((PrefixExpression&) expr, out);
653 case Expression::kPostfix_Kind:
654 return this->writePostfixExpression((PostfixExpression&) expr, out);
655 case Expression::kSwizzle_Kind:
656 return this->writeSwizzle((Swizzle&) expr, out);
657 case Expression::kVariableReference_Kind:
658 return this->writeVariableReference((VariableReference&) expr, out);
659 case Expression::kTernary_Kind:
660 return this->writeTernaryExpression((TernaryExpression&) expr, out);
661 case Expression::kIndex_Kind:
662 return this->writeIndexExpression((IndexExpression&) expr, out);
663 default:
664 ABORT("unsupported expression: %s", expr.description().c_str());
665 }
666 return -1;
667}
668
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400669SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700670 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400671 SkASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -0700672 int32_t intrinsicId;
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400673 if (c.fArguments.size() > 0) {
674 const Type& type = c.fArguments[0]->fType;
675 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
676 intrinsicId = std::get<1>(intrinsic->second);
677 } else if (is_signed(fContext, type)) {
678 intrinsicId = std::get<2>(intrinsic->second);
679 } else if (is_unsigned(fContext, type)) {
680 intrinsicId = std::get<3>(intrinsic->second);
681 } else if (is_bool(fContext, type)) {
682 intrinsicId = std::get<4>(intrinsic->second);
683 } else {
684 intrinsicId = std::get<1>(intrinsic->second);
685 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700686 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400687 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700688 }
689 switch (std::get<0>(intrinsic->second)) {
690 case kGLSL_STD_450_IntrinsicKind: {
691 SpvId result = this->nextId();
692 std::vector<SpvId> arguments;
693 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400694 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
695 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
696 } else {
697 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
698 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700699 }
700 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700701 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700702 this->writeWord(result, out);
703 this->writeWord(fGLSLExtendedInstructions, out);
704 this->writeWord(intrinsicId, out);
705 for (SpvId id : arguments) {
706 this->writeWord(id, out);
707 }
708 return result;
709 }
710 case kSPIRV_IntrinsicKind: {
711 SpvId result = this->nextId();
712 std::vector<SpvId> arguments;
713 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400714 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
715 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
716 } else {
717 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
718 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700719 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400720 if (c.fType != *fContext.fVoid_Type) {
721 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
722 this->writeWord(this->getType(c.fType), out);
723 this->writeWord(result, out);
724 } else {
725 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
726 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700727 for (SpvId id : arguments) {
728 this->writeWord(id, out);
729 }
730 return result;
731 }
732 case kSpecial_IntrinsicKind:
733 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
734 default:
735 ABORT("unsupported intrinsic kind");
736 }
737}
738
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500739std::vector<SpvId> SPIRVCodeGenerator::vectorize(
740 const std::vector<std::unique_ptr<Expression>>& args,
741 OutputStream& out) {
742 int vectorSize = 0;
743 for (const auto& a : args) {
744 if (a->fType.kind() == Type::kVector_Kind) {
745 if (vectorSize) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400746 SkASSERT(a->fType.columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500747 }
748 else {
749 vectorSize = a->fType.columns();
750 }
751 }
752 }
753 std::vector<SpvId> result;
754 for (const auto& a : args) {
755 SpvId raw = this->writeExpression(*a, out);
756 if (vectorSize && a->fType.kind() == Type::kScalar_Kind) {
757 SpvId vector = this->nextId();
758 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
759 this->writeWord(this->getType(a->fType.toCompound(fContext, vectorSize, 1)), out);
760 this->writeWord(vector, out);
761 for (int i = 0; i < vectorSize; i++) {
762 this->writeWord(raw, out);
763 }
764 result.push_back(vector);
765 } else {
766 result.push_back(raw);
767 }
768 }
769 return result;
770}
771
772void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
773 SpvId signedInst, SpvId unsignedInst,
774 const std::vector<SpvId>& args,
775 OutputStream& out) {
776 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
777 this->writeWord(this->getType(type), out);
778 this->writeWord(id, out);
779 this->writeWord(fGLSLExtendedInstructions, out);
780
781 if (is_float(fContext, type)) {
782 this->writeWord(floatInst, out);
783 } else if (is_signed(fContext, type)) {
784 this->writeWord(signedInst, out);
785 } else if (is_unsigned(fContext, type)) {
786 this->writeWord(unsignedInst, out);
787 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400788 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500789 }
790 for (SpvId a : args) {
791 this->writeWord(a, out);
792 }
793}
794
Greg Daniel64773e62016-11-22 09:44:03 -0500795SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400796 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700797 SpvId result = this->nextId();
798 switch (kind) {
799 case kAtan_SpecialIntrinsic: {
800 std::vector<SpvId> arguments;
801 for (size_t i = 0; i < c.fArguments.size(); i++) {
802 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
803 }
804 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700805 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700806 this->writeWord(result, out);
807 this->writeWord(fGLSLExtendedInstructions, out);
808 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
809 for (SpvId id : arguments) {
810 this->writeWord(id, out);
811 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400812 break;
813 }
814 case kSubpassLoad_SpecialIntrinsic: {
815 SpvId img = this->writeExpression(*c.fArguments[0], out);
816 std::vector<std::unique_ptr<Expression>> args;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700817 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
818 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
819 Constructor ctor(-1, *fContext.fFloat2_Type, std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400820 SpvId coords = this->writeConstantVector(ctor);
821 if (1 == c.fArguments.size()) {
822 this->writeInstruction(SpvOpImageRead,
823 this->getType(c.fType),
824 result,
825 img,
826 coords,
827 out);
828 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400829 SkASSERT(2 == c.fArguments.size());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400830 SpvId sample = this->writeExpression(*c.fArguments[1], out);
831 this->writeInstruction(SpvOpImageRead,
832 this->getType(c.fType),
833 result,
834 img,
835 coords,
836 SpvImageOperandsSampleMask,
837 sample,
838 out);
839 }
840 break;
841 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700842 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500843 SpvOp_ op = SpvOpImageSampleImplicitLod;
844 switch (c.fArguments[0]->fType.dimensions()) {
845 case SpvDim1D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400846 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500847 op = SpvOpImageSampleProjImplicitLod;
848 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400849 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500850 }
851 break;
852 case SpvDim2D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400853 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500854 op = SpvOpImageSampleProjImplicitLod;
855 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400856 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500857 }
858 break;
859 case SpvDim3D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400860 if (c.fArguments[1]->fType == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500861 op = SpvOpImageSampleProjImplicitLod;
862 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400863 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500864 }
865 break;
866 case SpvDimCube: // fall through
867 case SpvDimRect: // fall through
868 case SpvDimBuffer: // fall through
869 case SpvDimSubpassData:
870 break;
871 }
ethannicholasd598f792016-07-25 10:08:54 -0700872 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700873 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
874 SpvId uv = this->writeExpression(*c.fArguments[1], out);
875 if (c.fArguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500876 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700877 SpvImageOperandsBiasMask,
878 this->writeExpression(*c.fArguments[2], out),
879 out);
880 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400881 SkASSERT(c.fArguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500882 if (fProgram.fSettings.fSharpenTextures) {
883 FloatLiteral lodBias(fContext, -1, -0.5);
884 this->writeInstruction(op, type, result, sampler, uv,
885 SpvImageOperandsBiasMask,
886 this->writeFloatLiteral(lodBias),
887 out);
888 } else {
889 this->writeInstruction(op, type, result, sampler, uv,
890 out);
891 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700892 }
893 break;
894 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500895 case kMod_SpecialIntrinsic: {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500896 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400897 SkASSERT(args.size() == 2);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500898 const Type& operandType = c.fArguments[0]->fType;
899 SpvOp_ op;
900 if (is_float(fContext, operandType)) {
901 op = SpvOpFMod;
902 } else if (is_signed(fContext, operandType)) {
903 op = SpvOpSMod;
904 } else if (is_unsigned(fContext, operandType)) {
905 op = SpvOpUMod;
906 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400907 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500908 return 0;
909 }
910 this->writeOpCode(op, 5, out);
911 this->writeWord(this->getType(operandType), out);
912 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500913 this->writeWord(args[0], out);
914 this->writeWord(args[1], out);
915 break;
916 }
917 case kClamp_SpecialIntrinsic: {
918 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400919 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500920 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
921 GLSLstd450UClamp, args, out);
922 break;
923 }
924 case kMax_SpecialIntrinsic: {
925 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400926 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500927 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMax, GLSLstd450SMax,
928 GLSLstd450UMax, args, out);
929 break;
930 }
931 case kMin_SpecialIntrinsic: {
932 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400933 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500934 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMin, GLSLstd450SMin,
935 GLSLstd450UMin, args, out);
936 break;
937 }
938 case kMix_SpecialIntrinsic: {
939 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400940 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500941 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMix, SpvOpUndef,
942 SpvOpUndef, args, out);
943 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500944 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700945 }
946 return result;
947}
948
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400949SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700950 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -0700951 if (entry == fFunctionMap.end()) {
952 return this->writeIntrinsicCall(c, out);
953 }
954 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
955 std::vector<std::tuple<SpvId, SpvId, std::unique_ptr<LValue>>> lvalues;
956 std::vector<SpvId> arguments;
957 for (size_t i = 0; i < c.fArguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500958 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -0700959 // passed directly
960 SpvId tmpVar;
961 // if we need a temporary var to store this argument, this is the value to store in the var
962 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -0700963 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700964 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
965 SpvId ptr = lv->getPointer();
966 if (ptr) {
967 arguments.push_back(ptr);
968 continue;
969 } else {
970 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
971 // copy it into a temp, call the function, read the value out of the temp, and then
972 // update the lvalue.
973 tmpValueId = lv->load(out);
974 tmpVar = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -0700975 lvalues.push_back(std::make_tuple(tmpVar, this->getType(c.fArguments[i]->fType),
ethannicholasb3058bd2016-07-01 08:22:01 -0700976 std::move(lv)));
977 }
978 } else {
979 // see getFunctionType for an explanation of why we're always using pointer parameters
980 tmpValueId = this->writeExpression(*c.fArguments[i], out);
981 tmpVar = this->nextId();
982 }
Greg Daniel64773e62016-11-22 09:44:03 -0500983 this->writeInstruction(SpvOpVariable,
984 this->getPointerType(c.fArguments[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -0700985 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -0500986 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -0700987 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -0700988 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700989 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
990 arguments.push_back(tmpVar);
991 }
992 SpvId result = this->nextId();
993 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700994 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700995 this->writeWord(result, out);
996 this->writeWord(entry->second, out);
997 for (SpvId id : arguments) {
998 this->writeWord(id, out);
999 }
1000 // now that the call is complete, we may need to update some lvalues with the new values of out
1001 // arguments
1002 for (const auto& tuple : lvalues) {
1003 SpvId load = this->nextId();
1004 this->writeInstruction(SpvOpLoad, std::get<1>(tuple), load, std::get<0>(tuple), out);
1005 std::get<2>(tuple)->store(load, out);
1006 }
1007 return result;
1008}
1009
ethannicholasf789b382016-08-03 12:43:36 -07001010SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001011 SkASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001012 SpvId result = this->nextId();
1013 std::vector<SpvId> arguments;
1014 for (size_t i = 0; i < c.fArguments.size(); i++) {
1015 arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1016 }
ethannicholasd598f792016-07-25 10:08:54 -07001017 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001018 if (c.fArguments.size() == 1) {
1019 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001020 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001021 this->writeWord(type, fConstantBuffer);
1022 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001023 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001024 this->writeWord(arguments[0], fConstantBuffer);
1025 }
1026 } else {
Greg Daniel64773e62016-11-22 09:44:03 -05001027 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001028 fConstantBuffer);
1029 this->writeWord(type, fConstantBuffer);
1030 this->writeWord(result, fConstantBuffer);
1031 for (SpvId id : arguments) {
1032 this->writeWord(id, fConstantBuffer);
1033 }
1034 }
1035 return result;
1036}
1037
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001038SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001039 SkASSERT(c.fType.isFloat());
1040 SkASSERT(c.fArguments.size() == 1);
1041 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001042 SpvId result = this->nextId();
1043 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001044 if (c.fArguments[0]->fType.isSigned()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001045 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001046 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001047 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001048 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Greg Daniel64773e62016-11-22 09:44:03 -05001049 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001050 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001051 }
1052 return result;
1053}
1054
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001055SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001056 SkASSERT(c.fType.isSigned());
1057 SkASSERT(c.fArguments.size() == 1);
1058 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001059 SpvId result = this->nextId();
1060 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001061 if (c.fArguments[0]->fType.isFloat()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001062 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001063 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001064 }
1065 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001066 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001067 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001068 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001069 }
1070 return result;
1071}
1072
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001073SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001074 SkASSERT(c.fType.isUnsigned());
1075 SkASSERT(c.fArguments.size() == 1);
1076 SkASSERT(c.fArguments[0]->fType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001077 SpvId result = this->nextId();
1078 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001079 if (c.fArguments[0]->fType.isFloat()) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001080 this->writeInstruction(SpvOpConvertFToU, this->getType(c.fType), result, parameter,
1081 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001082 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001083 SkASSERT(c.fArguments[0]->fType.isSigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001084 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
1085 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001086 }
1087 return result;
1088}
1089
Ethan Nicholas84645e32017-02-09 13:57:14 -05001090void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001091 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001092 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001093 SpvId zeroId = this->writeFloatLiteral(zero);
1094 std::vector<SpvId> columnIds;
1095 for (int column = 0; column < type.columns(); column++) {
1096 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1097 out);
1098 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1099 out);
1100 SpvId columnId = this->nextId();
1101 this->writeWord(columnId, out);
1102 columnIds.push_back(columnId);
1103 for (int row = 0; row < type.columns(); row++) {
1104 this->writeWord(row == column ? diagonal : zeroId, out);
1105 }
1106 }
1107 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1108 out);
1109 this->writeWord(this->getType(type), out);
1110 this->writeWord(id, out);
1111 for (SpvId id : columnIds) {
1112 this->writeWord(id, out);
1113 }
1114}
1115
1116void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001117 const Type& dstType, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001118 SkASSERT(srcType.kind() == Type::kMatrix_Kind);
1119 SkASSERT(dstType.kind() == Type::kMatrix_Kind);
1120 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001121 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1122 srcType.rows(),
1123 1));
1124 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1125 dstType.rows(),
1126 1));
1127 SpvId zeroId;
1128 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001129 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001130 zeroId = this->writeFloatLiteral(zero);
1131 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001132 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001133 zeroId = this->writeIntLiteral(zero);
1134 } else {
1135 ABORT("unsupported matrix component type");
1136 }
1137 SpvId zeroColumn = 0;
1138 SpvId columns[4];
1139 for (int i = 0; i < dstType.columns(); i++) {
1140 if (i < srcType.columns()) {
1141 // we're still inside the src matrix, copy the column
1142 SpvId srcColumn = this->nextId();
1143 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
1144 SpvId dstColumn;
1145 if (srcType.rows() == dstType.rows()) {
1146 // columns are equal size, don't need to do anything
1147 dstColumn = srcColumn;
1148 }
1149 else if (dstType.rows() > srcType.rows()) {
1150 // dst column is bigger, need to zero-pad it
1151 dstColumn = this->nextId();
1152 int delta = dstType.rows() - srcType.rows();
1153 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1154 this->writeWord(dstColumnType, out);
1155 this->writeWord(dstColumn, out);
1156 this->writeWord(srcColumn, out);
1157 for (int i = 0; i < delta; ++i) {
1158 this->writeWord(zeroId, out);
1159 }
1160 }
1161 else {
1162 // dst column is smaller, need to swizzle the src column
1163 dstColumn = this->nextId();
1164 int count = dstType.rows();
1165 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1166 this->writeWord(dstColumnType, out);
1167 this->writeWord(dstColumn, out);
1168 this->writeWord(srcColumn, out);
1169 this->writeWord(srcColumn, out);
1170 for (int i = 0; i < count; i++) {
1171 this->writeWord(i, out);
1172 }
1173 }
1174 columns[i] = dstColumn;
1175 } else {
1176 // we're past the end of the src matrix, need a vector of zeroes
1177 if (!zeroColumn) {
1178 zeroColumn = this->nextId();
1179 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1180 this->writeWord(dstColumnType, out);
1181 this->writeWord(zeroColumn, out);
1182 for (int i = 0; i < dstType.rows(); ++i) {
1183 this->writeWord(zeroId, out);
1184 }
1185 }
1186 columns[i] = zeroColumn;
1187 }
1188 }
1189 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1190 this->writeWord(this->getType(dstType), out);
1191 this->writeWord(id, out);
1192 for (int i = 0; i < dstType.columns(); i++) {
1193 this->writeWord(columns[i], out);
1194 }
Ethan Nicholas84645e32017-02-09 13:57:14 -05001195}
1196
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001197SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001198 SkASSERT(c.fType.kind() == Type::kMatrix_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001199 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1200 // an instruction
1201 std::vector<SpvId> arguments;
1202 for (size_t i = 0; i < c.fArguments.size(); i++) {
1203 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1204 }
1205 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001206 int rows = c.fType.rows();
1207 int columns = c.fType.columns();
Ethan Nicholas84645e32017-02-09 13:57:14 -05001208 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1209 this->writeUniformScaleMatrix(result, arguments[0], c.fType, out);
1210 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kMatrix_Kind) {
1211 this->writeMatrixCopy(result, arguments[0], c.fArguments[0]->fType, c.fType, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001212 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kVector_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001213 SkASSERT(c.fType.rows() == 2 && c.fType.columns() == 2);
1214 SkASSERT(c.fArguments[0]->fType.columns() == 4);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001215 SpvId componentType = this->getType(c.fType.componentType());
1216 SpvId v[4];
1217 for (int i = 0; i < 4; ++i) {
1218 v[i] = this->nextId();
1219 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i, out);
1220 }
1221 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, 2, 1));
1222 SpvId column1 = this->nextId();
1223 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1224 SpvId column2 = this->nextId();
1225 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
1226 this->writeInstruction(SpvOpCompositeConstruct, this->getType(c.fType), result, column1,
1227 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001228 } else {
1229 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001230 // ids of vectors and scalars we have written to the current column so far
1231 std::vector<SpvId> currentColumn;
1232 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001233 int currentCount = 0;
1234 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001235 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind &&
1236 c.fArguments[i]->fType.columns() == c.fType.rows()) {
1237 // this is a complete column by itself
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001238 SkASSERT(currentCount == 0);
ethannicholasb3058bd2016-07-01 08:22:01 -07001239 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001240 } else {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001241 if (c.fArguments[i]->fType.columns() == 1) {
1242 currentColumn.push_back(arguments[i]);
1243 } else {
1244 SpvId componentType = this->getType(c.fArguments[i]->fType.componentType());
Ethan Nicholas811b9442018-05-11 13:16:03 -04001245 for (int j = 0; j < c.fArguments[i]->fType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001246 SpvId swizzle = this->nextId();
1247 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1248 arguments[i], j, out);
1249 currentColumn.push_back(swizzle);
1250 }
1251 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001252 currentCount += c.fArguments[i]->fType.columns();
1253 if (currentCount == rows) {
1254 currentCount = 0;
1255 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn.size(), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001256 this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows,
1257 1)),
ethannicholasb3058bd2016-07-01 08:22:01 -07001258 out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001259 SpvId columnId = this->nextId();
1260 this->writeWord(columnId, out);
1261 columnIds.push_back(columnId);
1262 for (SpvId id : currentColumn) {
1263 this->writeWord(id, out);
1264 }
1265 currentColumn.clear();
ethannicholasb3058bd2016-07-01 08:22:01 -07001266 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001267 SkASSERT(currentCount < rows);
ethannicholasb3058bd2016-07-01 08:22:01 -07001268 }
1269 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001270 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001271 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001272 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001273 this->writeWord(result, out);
1274 for (SpvId id : columnIds) {
1275 this->writeWord(id, out);
1276 }
1277 }
1278 return result;
1279}
1280
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001281SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001282 SkASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001283 if (c.isConstant()) {
1284 return this->writeConstantVector(c);
1285 }
1286 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1287 // an instruction
1288 std::vector<SpvId> arguments;
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001289 for (size_t i = 0; i < c.fArguments.size(); i++) {
1290 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
1291 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1292 // extract the components and convert them in that case manually. On top of that,
1293 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1294 // doesn't handle vector arguments at all, so we always extract vector components and
1295 // pass them into OpCreateComposite individually.
1296 SpvId vec = this->writeExpression(*c.fArguments[i], out);
1297 SpvOp_ op = SpvOpUndef;
1298 const Type& src = c.fArguments[i]->fType.componentType();
1299 const Type& dst = c.fType.componentType();
1300 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1301 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1302 if (c.fArguments.size() == 1) {
1303 return vec;
1304 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001305 } else if (src == *fContext.fInt_Type ||
1306 src == *fContext.fShort_Type ||
1307 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001308 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001309 } else if (src == *fContext.fUInt_Type ||
1310 src == *fContext.fUShort_Type ||
1311 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001312 op = SpvOpConvertUToF;
1313 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001314 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001315 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001316 } else if (dst == *fContext.fInt_Type ||
1317 dst == *fContext.fShort_Type ||
1318 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001319 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1320 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001321 } else if (src == *fContext.fInt_Type ||
1322 src == *fContext.fShort_Type ||
1323 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001324 if (c.fArguments.size() == 1) {
1325 return vec;
1326 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001327 } else if (src == *fContext.fUInt_Type ||
1328 src == *fContext.fUShort_Type ||
1329 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001330 op = SpvOpBitcast;
1331 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001332 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001333 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001334 } else if (dst == *fContext.fUInt_Type ||
1335 dst == *fContext.fUShort_Type ||
1336 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001337 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1338 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001339 } else if (src == *fContext.fInt_Type ||
1340 src == *fContext.fShort_Type ||
1341 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001342 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001343 } else if (src == *fContext.fUInt_Type ||
1344 src == *fContext.fUShort_Type ||
1345 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001346 if (c.fArguments.size() == 1) {
1347 return vec;
1348 }
1349 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001350 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001351 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001352 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001353 for (int j = 0; j < c.fArguments[i]->fType.columns(); j++) {
1354 SpvId swizzle = this->nextId();
1355 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1356 out);
1357 if (op != SpvOpUndef) {
1358 SpvId cast = this->nextId();
1359 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1360 arguments.push_back(cast);
1361 } else {
1362 arguments.push_back(swizzle);
1363 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001364 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001365 } else {
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001366 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1367 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001368 }
1369 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001370 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1371 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1372 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001373 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001374 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001375 this->writeWord(arguments[0], out);
1376 }
1377 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001378 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001379 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001380 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001381 this->writeWord(result, out);
1382 for (SpvId id : arguments) {
1383 this->writeWord(id, out);
1384 }
1385 }
1386 return result;
1387}
1388
Ethan Nicholasbd553222017-07-18 15:54:59 -04001389SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001390 SkASSERT(c.fType.kind() == Type::kArray_Kind);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001391 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1392 // an instruction
1393 std::vector<SpvId> arguments;
1394 for (size_t i = 0; i < c.fArguments.size(); i++) {
1395 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1396 }
1397 SpvId result = this->nextId();
1398 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
1399 this->writeWord(this->getType(c.fType), out);
1400 this->writeWord(result, out);
1401 for (SpvId id : arguments) {
1402 this->writeWord(id, out);
1403 }
1404 return result;
1405}
1406
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001407SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001408 if (c.fArguments.size() == 1 &&
1409 this->getActualType(c.fType) == this->getActualType(c.fArguments[0]->fType)) {
1410 return this->writeExpression(*c.fArguments[0], out);
1411 }
1412 if (c.fType == *fContext.fFloat_Type || c.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001413 return this->writeFloatConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001414 } else if (c.fType == *fContext.fInt_Type ||
1415 c.fType == *fContext.fShort_Type ||
1416 c.fType == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001417 return this->writeIntConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001418 } else if (c.fType == *fContext.fUInt_Type ||
1419 c.fType == *fContext.fUShort_Type ||
1420 c.fType == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001421 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001422 }
ethannicholasd598f792016-07-25 10:08:54 -07001423 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001424 case Type::kVector_Kind:
1425 return this->writeVectorConstructor(c, out);
1426 case Type::kMatrix_Kind:
1427 return this->writeMatrixConstructor(c, out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001428 case Type::kArray_Kind:
1429 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001430 default:
1431 ABORT("unsupported constructor: %s", c.description().c_str());
1432 }
1433}
1434
1435SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1436 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001437 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001438 return SpvStorageClassInput;
1439 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001440 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001441 return SpvStorageClassOutput;
1442 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001443 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001444 return SpvStorageClassPushConstant;
1445 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001446 return SpvStorageClassUniform;
1447 } else {
1448 return SpvStorageClassFunction;
1449 }
1450}
1451
ethannicholasf789b382016-08-03 12:43:36 -07001452SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001453 switch (expr.fKind) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001454 case Expression::kVariableReference_Kind: {
1455 const Variable& var = ((VariableReference&) expr).fVariable;
1456 if (var.fStorage != Variable::kGlobal_Storage) {
1457 return SpvStorageClassFunction;
1458 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001459 SpvStorageClass_ result = get_storage_class(var.fModifiers);
1460 if (result == SpvStorageClassFunction) {
1461 result = SpvStorageClassPrivate;
1462 }
1463 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001464 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001465 case Expression::kFieldAccess_Kind:
1466 return get_storage_class(*((FieldAccess&) expr).fBase);
1467 case Expression::kIndex_Kind:
1468 return get_storage_class(*((IndexExpression&) expr).fBase);
1469 default:
1470 return SpvStorageClassFunction;
1471 }
1472}
1473
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001474std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001475 std::vector<SpvId> chain;
1476 switch (expr.fKind) {
1477 case Expression::kIndex_Kind: {
1478 IndexExpression& indexExpr = (IndexExpression&) expr;
1479 chain = this->getAccessChain(*indexExpr.fBase, out);
1480 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1481 break;
1482 }
1483 case Expression::kFieldAccess_Kind: {
1484 FieldAccess& fieldExpr = (FieldAccess&) expr;
1485 chain = this->getAccessChain(*fieldExpr.fBase, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001486 IntLiteral index(fContext, -1, fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001487 chain.push_back(this->writeIntLiteral(index));
1488 break;
1489 }
1490 default:
1491 chain.push_back(this->getLValue(expr, out)->getPointer());
1492 }
1493 return chain;
1494}
1495
1496class PointerLValue : public SPIRVCodeGenerator::LValue {
1497public:
Greg Daniel64773e62016-11-22 09:44:03 -05001498 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type)
ethannicholasb3058bd2016-07-01 08:22:01 -07001499 : fGen(gen)
1500 , fPointer(pointer)
1501 , fType(type) {}
1502
1503 virtual SpvId getPointer() override {
1504 return fPointer;
1505 }
1506
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001507 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001508 SpvId result = fGen.nextId();
1509 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
1510 return result;
1511 }
1512
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001513 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001514 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1515 }
1516
1517private:
1518 SPIRVCodeGenerator& fGen;
1519 const SpvId fPointer;
1520 const SpvId fType;
1521};
1522
1523class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1524public:
Greg Daniel64773e62016-11-22 09:44:03 -05001525 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
ethannicholasb3058bd2016-07-01 08:22:01 -07001526 const Type& baseType, const Type& swizzleType)
1527 : fGen(gen)
1528 , fVecPointer(vecPointer)
1529 , fComponents(components)
1530 , fBaseType(baseType)
1531 , fSwizzleType(swizzleType) {}
1532
1533 virtual SpvId getPointer() override {
1534 return 0;
1535 }
1536
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001537 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001538 SpvId base = fGen.nextId();
1539 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1540 SpvId result = fGen.nextId();
1541 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1542 fGen.writeWord(fGen.getType(fSwizzleType), out);
1543 fGen.writeWord(result, out);
1544 fGen.writeWord(base, out);
1545 fGen.writeWord(base, out);
1546 for (int component : fComponents) {
1547 fGen.writeWord(component, out);
1548 }
1549 return result;
1550 }
1551
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001552 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001553 // use OpVectorShuffle to mix and match the vector components. We effectively create
1554 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001555 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001556 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001557 // float3L = ...;
1558 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001559 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001560 // 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 -07001561 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1562 // (3, 1, 4).
1563 SpvId base = fGen.nextId();
1564 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1565 SpvId shuffle = fGen.nextId();
1566 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1567 fGen.writeWord(fGen.getType(fBaseType), out);
1568 fGen.writeWord(shuffle, out);
1569 fGen.writeWord(base, out);
1570 fGen.writeWord(value, out);
1571 for (int i = 0; i < fBaseType.columns(); i++) {
1572 // current offset into the virtual vector, defaults to pulling the unmodified
1573 // value from the left side
1574 int offset = i;
1575 // check to see if we are writing this component
1576 for (size_t j = 0; j < fComponents.size(); j++) {
1577 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001578 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001579 // the correct component of the right side instead of preserving the
1580 // value from the left
1581 offset = (int) (j + fBaseType.columns());
1582 break;
1583 }
1584 }
1585 fGen.writeWord(offset, out);
1586 }
1587 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1588 }
1589
1590private:
1591 SPIRVCodeGenerator& fGen;
1592 const SpvId fVecPointer;
1593 const std::vector<int>& fComponents;
1594 const Type& fBaseType;
1595 const Type& fSwizzleType;
1596};
1597
Greg Daniel64773e62016-11-22 09:44:03 -05001598std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001599 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001600 switch (expr.fKind) {
1601 case Expression::kVariableReference_Kind: {
Ethan Nicholas5226b772018-05-03 16:20:41 -04001602 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07001603 const Variable& var = ((VariableReference&) expr).fVariable;
Ethan Nicholas5226b772018-05-03 16:20:41 -04001604 if (var.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
1605 type = this->getType(Type("sk_in", Type::kArray_Kind, var.fType.componentType(),
1606 fSkInCount));
1607 } else {
1608 type = this->getType(expr.fType);
1609 }
ethannicholasd598f792016-07-25 10:08:54 -07001610 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001611 SkASSERT(entry != fVariableMap.end());
Ethan Nicholas5226b772018-05-03 16:20:41 -04001612 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(*this,
1613 entry->second,
1614 type));
ethannicholasb3058bd2016-07-01 08:22:01 -07001615 }
1616 case Expression::kIndex_Kind: // fall through
1617 case Expression::kFieldAccess_Kind: {
1618 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1619 SpvId member = this->nextId();
1620 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001621 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001622 this->writeWord(member, out);
1623 for (SpvId idx : chain) {
1624 this->writeWord(idx, out);
1625 }
1626 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -04001627 *this,
1628 member,
1629 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001630 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001631 case Expression::kSwizzle_Kind: {
1632 Swizzle& swizzle = (Swizzle&) expr;
1633 size_t count = swizzle.fComponents.size();
1634 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001635 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001636 if (count == 1) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001637 IntLiteral index(fContext, -1, swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001638 SpvId member = this->nextId();
1639 this->writeInstruction(SpvOpAccessChain,
Greg Daniel64773e62016-11-22 09:44:03 -05001640 this->getPointerType(swizzle.fType,
1641 get_storage_class(*swizzle.fBase)),
1642 member,
1643 base,
1644 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001645 out);
1646 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1647 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001648 member,
ethannicholasd598f792016-07-25 10:08:54 -07001649 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001650 } else {
1651 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
Greg Daniel64773e62016-11-22 09:44:03 -05001652 *this,
1653 base,
1654 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001655 swizzle.fBase->fType,
1656 expr.fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07001657 }
1658 }
Ethan Nicholasa583b812018-01-18 13:32:11 -05001659 case Expression::kTernary_Kind: {
1660 TernaryExpression& t = (TernaryExpression&) expr;
1661 SpvId test = this->writeExpression(*t.fTest, out);
1662 SpvId end = this->nextId();
1663 SpvId ifTrueLabel = this->nextId();
1664 SpvId ifFalseLabel = this->nextId();
1665 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1666 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1667 this->writeLabel(ifTrueLabel, out);
1668 SpvId ifTrue = this->getLValue(*t.fIfTrue, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001669 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001670 this->writeInstruction(SpvOpBranch, end, out);
1671 ifTrueLabel = fCurrentBlock;
1672 SpvId ifFalse = this->getLValue(*t.fIfFalse, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001673 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001674 ifFalseLabel = fCurrentBlock;
1675 this->writeInstruction(SpvOpBranch, end, out);
1676 SpvId result = this->nextId();
1677 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1678 ifTrueLabel, ifFalse, ifFalseLabel, out);
1679 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1680 *this,
1681 result,
1682 this->getType(expr.fType)));
1683 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001684 default:
1685 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001686 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001687 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1688 // caught by IRGenerator
1689 SpvId result = this->nextId();
1690 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001691 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1692 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001693 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1694 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1695 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001696 result,
ethannicholasd598f792016-07-25 10:08:54 -07001697 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001698 }
1699}
1700
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001701SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001702 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001703 auto entry = fVariableMap.find(&ref.fVariable);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001704 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001705 SpvId var = entry->second;
ethannicholasd598f792016-07-25 10:08:54 -07001706 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001707 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
1708 fProgram.fSettings.fFlipY) {
1709 // need to remap to a top-left coordinate system
1710 if (fRTHeightStructId == (SpvId) -1) {
1711 // height variable hasn't been written yet
Ethan Nicholas8feeff92017-03-30 14:11:58 -04001712 std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors));
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001713 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001714 std::vector<Type::Field> fields;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001715 fields.emplace_back(Modifiers(), SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1716 StringFragment name("sksl_synthetic_uniforms");
1717 Type intfStruct(-1, name, fields);
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001718 Layout layout(0, -1, -1, 1, -1, -1, -1, -1, Layout::Format::kUnspecified,
1719 Layout::kUnspecified_Primitive, -1, -1, "", Layout::kNo_Key,
1720 StringFragment());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001721 Variable* intfVar = new Variable(-1,
Ethan Nicholas8feeff92017-03-30 14:11:58 -04001722 Modifiers(layout, Modifiers::kUniform_Flag),
1723 name,
1724 intfStruct,
Ethan Nicholas82a62d22017-11-07 14:42:10 +00001725 Variable::kGlobal_Storage);
Ethan Nicholas8feeff92017-03-30 14:11:58 -04001726 fSynthetics.takeOwnership(intfVar);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001727 InterfaceBlock intf(-1, intfVar, name, String(""),
Ethan Nicholas50afc172017-02-16 14:49:57 -05001728 std::vector<std::unique_ptr<Expression>>(), st);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001729 fRTHeightStructId = this->writeInterfaceBlock(intf);
1730 fRTHeightFieldIndex = 0;
1731 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001732 SkASSERT(fRTHeightFieldIndex != (SpvId) -1);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001733 // write float4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, 1.0)
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001734 SpvId xId = this->nextId();
1735 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1736 result, 0, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001737 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001738 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
Ethan Nicholas613a6972016-12-29 16:36:40 -05001739 SpvId heightPtr = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001740 this->writeOpCode(SpvOpAccessChain, 5, out);
1741 this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out);
Ethan Nicholas613a6972016-12-29 16:36:40 -05001742 this->writeWord(heightPtr, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001743 this->writeWord(fRTHeightStructId, out);
1744 this->writeWord(fieldIndexId, out);
Ethan Nicholas613a6972016-12-29 16:36:40 -05001745 SpvId heightRead = this->nextId();
1746 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1747 heightPtr, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001748 SpvId rawYId = this->nextId();
1749 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1750 result, 1, out);
1751 SpvId flippedYId = this->nextId();
1752 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
1753 heightRead, rawYId, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001754 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001755 SpvId zeroId = writeFloatLiteral(zero);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001756 FloatLiteral one(fContext, -1, 1.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001757 SpvId oneId = writeFloatLiteral(one);
1758 SpvId flipped = this->nextId();
1759 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001760 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001761 this->writeWord(flipped, out);
1762 this->writeWord(xId, out);
1763 this->writeWord(flippedYId, out);
1764 this->writeWord(zeroId, out);
1765 this->writeWord(oneId, out);
1766 return flipped;
1767 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001768 return result;
1769}
1770
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001771SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001772 return getLValue(expr, out)->load(out);
1773}
1774
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001775SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001776 return getLValue(f, out)->load(out);
1777}
1778
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001779SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001780 SpvId base = this->writeExpression(*swizzle.fBase, out);
1781 SpvId result = this->nextId();
1782 size_t count = swizzle.fComponents.size();
1783 if (count == 1) {
Greg Daniel64773e62016-11-22 09:44:03 -05001784 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
1785 swizzle.fComponents[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001786 } else {
1787 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
ethannicholasd598f792016-07-25 10:08:54 -07001788 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001789 this->writeWord(result, out);
1790 this->writeWord(base, out);
1791 this->writeWord(base, out);
1792 for (int component : swizzle.fComponents) {
1793 this->writeWord(component, out);
1794 }
1795 }
1796 return result;
1797}
1798
Greg Daniel64773e62016-11-22 09:44:03 -05001799SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1800 const Type& operandType, SpvId lhs,
1801 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001802 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001803 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001804 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001805 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001806 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001807 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001808 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001809 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001810 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001811 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
1812 } else {
1813 ABORT("invalid operandType: %s", operandType.description().c_str());
1814 }
1815 return result;
1816}
1817
1818bool is_assignment(Token::Kind op) {
1819 switch (op) {
1820 case Token::EQ: // fall through
1821 case Token::PLUSEQ: // fall through
1822 case Token::MINUSEQ: // fall through
1823 case Token::STAREQ: // fall through
1824 case Token::SLASHEQ: // fall through
1825 case Token::PERCENTEQ: // fall through
1826 case Token::SHLEQ: // fall through
1827 case Token::SHREQ: // fall through
1828 case Token::BITWISEOREQ: // fall through
1829 case Token::BITWISEXOREQ: // fall through
1830 case Token::BITWISEANDEQ: // fall through
1831 case Token::LOGICALOREQ: // fall through
1832 case Token::LOGICALXOREQ: // fall through
1833 case Token::LOGICALANDEQ:
1834 return true;
1835 default:
1836 return false;
1837 }
1838}
1839
Ethan Nicholas48e24052018-03-14 13:51:39 -04001840SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
1841 OutputStream& out) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05001842 if (operandType.kind() == Type::kVector_Kind) {
1843 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001844 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05001845 return result;
1846 }
1847 return id;
1848}
1849
Ethan Nicholas68990be2017-07-13 09:36:52 -04001850SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
1851 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04001852 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04001853 OutputStream& out) {
1854 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001855 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0df21132018-07-10 09:37:51 -04001856 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
1857 operandType.rows(),
1858 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04001859 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04001860 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04001861 1));
1862 SpvId boolType = this->getType(*fContext.fBool_Type);
1863 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04001864 for (int i = 0; i < operandType.columns(); i++) {
1865 SpvId columnL = this->nextId();
1866 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
1867 SpvId columnR = this->nextId();
1868 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04001869 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04001870 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
1871 SpvId merge = this->nextId();
1872 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04001873 if (result != 0) {
1874 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04001875 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04001876 result = next;
1877 }
1878 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04001879 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04001880 }
1881 }
1882 return result;
1883}
1884
Ethan Nicholas0df21132018-07-10 09:37:51 -04001885SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
1886 SpvId rhs, SpvOp_ floatOperator,
1887 SpvOp_ intOperator,
1888 OutputStream& out) {
1889 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
1890 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
1891 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
1892 operandType.rows(),
1893 1));
1894 SpvId columns[4];
1895 for (int i = 0; i < operandType.columns(); i++) {
1896 SpvId columnL = this->nextId();
1897 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
1898 SpvId columnR = this->nextId();
1899 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
1900 columns[i] = this->nextId();
1901 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
1902 }
1903 SpvId result = this->nextId();
1904 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
1905 this->writeWord(this->getType(operandType), out);
1906 this->writeWord(result, out);
1907 for (int i = 0; i < operandType.columns(); i++) {
1908 this->writeWord(columns[i], out);
1909 }
1910 return result;
1911}
1912
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001913SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001914 // handle cases where we don't necessarily evaluate both LHS and RHS
1915 switch (b.fOperator) {
1916 case Token::EQ: {
1917 SpvId rhs = this->writeExpression(*b.fRight, out);
1918 this->getLValue(*b.fLeft, out)->store(rhs, out);
1919 return rhs;
1920 }
1921 case Token::LOGICALAND:
1922 return this->writeLogicalAnd(b, out);
1923 case Token::LOGICALOR:
1924 return this->writeLogicalOr(b, out);
1925 default:
1926 break;
1927 }
1928
1929 // "normal" operators
ethannicholasd598f792016-07-25 10:08:54 -07001930 const Type& resultType = b.fType;
ethannicholasb3058bd2016-07-01 08:22:01 -07001931 std::unique_ptr<LValue> lvalue;
1932 SpvId lhs;
1933 if (is_assignment(b.fOperator)) {
1934 lvalue = this->getLValue(*b.fLeft, out);
1935 lhs = lvalue->load(out);
1936 } else {
1937 lvalue = nullptr;
1938 lhs = this->writeExpression(*b.fLeft, out);
1939 }
1940 SpvId rhs = this->writeExpression(*b.fRight, out);
Ethan Nicholas6feb6912017-06-30 12:23:36 -04001941 if (b.fOperator == Token::COMMA) {
1942 return rhs;
1943 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001944 Type tmp("<invalid>");
Ethan Nicholas48e24052018-03-14 13:51:39 -04001945 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07001946 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04001947 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
1948 // handling in SPIR-V
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001949 if (this->getActualType(b.fLeft->fType) != this->getActualType(b.fRight->fType)) {
Greg Daniel64773e62016-11-22 09:44:03 -05001950 if (b.fLeft->fType.kind() == Type::kVector_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07001951 b.fRight->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001952 // promote number to vector
1953 SpvId vec = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001954 const Type& vecType = b.fLeft->fType;
1955 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
1956 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001957 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04001958 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001959 this->writeWord(rhs, out);
1960 }
1961 rhs = vec;
Ethan Nicholas48e24052018-03-14 13:51:39 -04001962 operandType = &b.fLeft->fType;
Greg Daniel64773e62016-11-22 09:44:03 -05001963 } else if (b.fRight->fType.kind() == Type::kVector_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07001964 b.fLeft->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001965 // promote number to vector
1966 SpvId vec = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001967 const Type& vecType = b.fRight->fType;
1968 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
1969 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001970 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04001971 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001972 this->writeWord(lhs, out);
1973 }
1974 lhs = vec;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001975 SkASSERT(!lvalue);
Ethan Nicholas48e24052018-03-14 13:51:39 -04001976 operandType = &b.fRight->fType;
ethannicholasd598f792016-07-25 10:08:54 -07001977 } else if (b.fLeft->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001978 SpvOp_ op;
ethannicholasd598f792016-07-25 10:08:54 -07001979 if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001980 op = SpvOpMatrixTimesMatrix;
ethannicholasd598f792016-07-25 10:08:54 -07001981 } else if (b.fRight->fType.kind() == Type::kVector_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001982 op = SpvOpMatrixTimesVector;
1983 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001984 SkASSERT(b.fRight->fType.kind() == Type::kScalar_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001985 op = SpvOpMatrixTimesScalar;
1986 }
1987 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001988 this->writeInstruction(op, this->getType(b.fType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001989 if (b.fOperator == Token::STAREQ) {
1990 lvalue->store(result, out);
1991 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001992 SkASSERT(b.fOperator == Token::STAR);
ethannicholasb3058bd2016-07-01 08:22:01 -07001993 }
1994 return result;
ethannicholasd598f792016-07-25 10:08:54 -07001995 } else if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001996 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001997 if (b.fLeft->fType.kind() == Type::kVector_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05001998 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(b.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07001999 lhs, rhs, out);
2000 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002001 SkASSERT(b.fLeft->fType.kind() == Type::kScalar_Kind);
Greg Daniel64773e62016-11-22 09:44:03 -05002002 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(b.fType), result, rhs,
ethannicholasb3058bd2016-07-01 08:22:01 -07002003 lhs, out);
2004 }
2005 if (b.fOperator == Token::STAREQ) {
2006 lvalue->store(result, out);
2007 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002008 SkASSERT(b.fOperator == Token::STAR);
ethannicholasb3058bd2016-07-01 08:22:01 -07002009 }
2010 return result;
2011 } else {
2012 ABORT("unsupported binary expression: %s", b.description().c_str());
2013 }
2014 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002015 tmp = this->getActualType(b.fLeft->fType);
2016 operandType = &tmp;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002017 SkASSERT(*operandType == this->getActualType(b.fRight->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002018 }
2019 switch (b.fOperator) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002020 case Token::EQEQ: {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002021 if (operandType->kind() == Type::kMatrix_Kind) {
2022 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002023 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002024 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002025 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002026 const Type* tmpType;
2027 if (operandType->kind() == Type::kVector_Kind) {
2028 tmpType = &fContext.fBool_Type->toCompound(fContext,
2029 operandType->columns(),
2030 operandType->rows());
2031 } else {
2032 tmpType = &resultType;
2033 }
2034 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002035 SpvOpFOrdEqual, SpvOpIEqual,
2036 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002037 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002038 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002039 case Token::NEQ:
Ethan Nicholas68990be2017-07-13 09:36:52 -04002040 if (operandType->kind() == Type::kMatrix_Kind) {
2041 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002042 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002043 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002044 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002045 const Type* tmpType;
2046 if (operandType->kind() == Type::kVector_Kind) {
2047 tmpType = &fContext.fBool_Type->toCompound(fContext,
2048 operandType->columns(),
2049 operandType->rows());
2050 } else {
2051 tmpType = &resultType;
2052 }
2053 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002054 SpvOpFOrdNotEqual, SpvOpINotEqual,
2055 SpvOpINotEqual, SpvOpLogicalNotEqual,
2056 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002057 *operandType, SpvOpAny, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002058 case Token::GT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002059 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002060 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2061 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002062 SpvOpUGreaterThan, SpvOpUndef, out);
2063 case Token::LT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002064 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002065 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002066 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
2067 case Token::GTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002068 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002069 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2070 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002071 SpvOpUGreaterThanEqual, SpvOpUndef, out);
2072 case Token::LTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002073 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002074 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2075 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002076 SpvOpULessThanEqual, SpvOpUndef, out);
2077 case Token::PLUS:
Ethan Nicholas0df21132018-07-10 09:37:51 -04002078 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2079 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2080 SkASSERT(b.fLeft->fType == b.fRight->fType);
2081 return this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2082 SpvOpFAdd, SpvOpIAdd, out);
2083 }
Greg Daniel64773e62016-11-22 09:44:03 -05002084 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002085 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2086 case Token::MINUS:
Ethan Nicholas0df21132018-07-10 09:37:51 -04002087 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2088 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2089 SkASSERT(b.fLeft->fType == b.fRight->fType);
2090 return this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2091 SpvOpFSub, SpvOpISub, out);
2092 }
Greg Daniel64773e62016-11-22 09:44:03 -05002093 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002094 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2095 case Token::STAR:
Greg Daniel64773e62016-11-22 09:44:03 -05002096 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002097 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002098 // matrix multiply
2099 SpvId result = this->nextId();
2100 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2101 lhs, rhs, out);
2102 return result;
2103 }
Greg Daniel64773e62016-11-22 09:44:03 -05002104 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002105 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2106 case Token::SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002107 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002108 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002109 case Token::PERCENT:
2110 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2111 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002112 case Token::SHL:
2113 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2114 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2115 SpvOpUndef, out);
2116 case Token::SHR:
2117 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2118 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2119 SpvOpUndef, out);
2120 case Token::BITWISEAND:
2121 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2122 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
2123 case Token::BITWISEOR:
2124 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2125 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
2126 case Token::BITWISEXOR:
2127 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2128 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002129 case Token::PLUSEQ: {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002130 SpvId result;
2131 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2132 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2133 SkASSERT(b.fLeft->fType == b.fRight->fType);
2134 result = this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2135 SpvOpFAdd, SpvOpIAdd, out);
2136 }
2137 else {
2138 result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002139 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002140 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002141 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002142 lvalue->store(result, out);
2143 return result;
2144 }
2145 case Token::MINUSEQ: {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002146 SpvId result;
2147 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2148 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2149 SkASSERT(b.fLeft->fType == b.fRight->fType);
2150 result = this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2151 SpvOpFSub, SpvOpISub, out);
2152 }
2153 else {
2154 result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002155 SpvOpISub, SpvOpISub, SpvOpUndef, out);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002156 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002157 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002158 lvalue->store(result, out);
2159 return result;
2160 }
2161 case Token::STAREQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002162 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002163 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002164 // matrix multiply
2165 SpvId result = this->nextId();
2166 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2167 lhs, rhs, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002168 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002169 lvalue->store(result, out);
2170 return result;
2171 }
Greg Daniel64773e62016-11-22 09:44:03 -05002172 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002173 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002174 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002175 lvalue->store(result, out);
2176 return result;
2177 }
2178 case Token::SLASHEQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002179 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002180 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002181 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002182 lvalue->store(result, out);
2183 return result;
2184 }
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002185 case Token::PERCENTEQ: {
2186 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2187 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002188 SkASSERT(lvalue);
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002189 lvalue->store(result, out);
2190 return result;
2191 }
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002192 case Token::SHLEQ: {
2193 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2194 SpvOpUndef, SpvOpShiftLeftLogical,
2195 SpvOpShiftLeftLogical, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002196 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002197 lvalue->store(result, out);
2198 return result;
2199 }
2200 case Token::SHREQ: {
2201 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2202 SpvOpUndef, SpvOpShiftRightArithmetic,
2203 SpvOpShiftRightLogical, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002204 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002205 lvalue->store(result, out);
2206 return result;
2207 }
2208 case Token::BITWISEANDEQ: {
2209 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2210 SpvOpUndef, SpvOpBitwiseAnd, SpvOpBitwiseAnd,
2211 SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002212 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002213 lvalue->store(result, out);
2214 return result;
2215 }
2216 case Token::BITWISEOREQ: {
2217 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2218 SpvOpUndef, SpvOpBitwiseOr, SpvOpBitwiseOr,
2219 SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002220 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002221 lvalue->store(result, out);
2222 return result;
2223 }
2224 case Token::BITWISEXOREQ: {
2225 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2226 SpvOpUndef, SpvOpBitwiseXor, SpvOpBitwiseXor,
2227 SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002228 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002229 lvalue->store(result, out);
2230 return result;
2231 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002232 default:
ethannicholasb3058bd2016-07-01 08:22:01 -07002233 ABORT("unsupported binary expression: %s", b.description().c_str());
2234 }
2235}
2236
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002237SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002238 SkASSERT(a.fOperator == Token::LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002239 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002240 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2241 SpvId lhs = this->writeExpression(*a.fLeft, out);
2242 SpvId rhsLabel = this->nextId();
2243 SpvId end = this->nextId();
2244 SpvId lhsBlock = fCurrentBlock;
2245 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2246 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2247 this->writeLabel(rhsLabel, out);
2248 SpvId rhs = this->writeExpression(*a.fRight, out);
2249 SpvId rhsBlock = fCurrentBlock;
2250 this->writeInstruction(SpvOpBranch, end, out);
2251 this->writeLabel(end, out);
2252 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002253 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002254 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002255 return result;
2256}
2257
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002258SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002259 SkASSERT(o.fOperator == Token::LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002260 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002261 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2262 SpvId lhs = this->writeExpression(*o.fLeft, out);
2263 SpvId rhsLabel = this->nextId();
2264 SpvId end = this->nextId();
2265 SpvId lhsBlock = fCurrentBlock;
2266 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2267 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2268 this->writeLabel(rhsLabel, out);
2269 SpvId rhs = this->writeExpression(*o.fRight, out);
2270 SpvId rhsBlock = fCurrentBlock;
2271 this->writeInstruction(SpvOpBranch, end, out);
2272 this->writeLabel(end, out);
2273 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002274 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002275 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002276 return result;
2277}
2278
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002279SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002280 SpvId test = this->writeExpression(*t.fTest, out);
2281 if (t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
2282 // both true and false are constants, can just use OpSelect
2283 SpvId result = this->nextId();
2284 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2285 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
Greg Daniel64773e62016-11-22 09:44:03 -05002286 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002287 out);
2288 return result;
2289 }
Greg Daniel64773e62016-11-22 09:44:03 -05002290 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002291 // Adreno. Switched to storing the result in a temp variable as glslang does.
2292 SpvId var = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002293 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002294 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002295 SpvId trueLabel = this->nextId();
2296 SpvId falseLabel = this->nextId();
2297 SpvId end = this->nextId();
2298 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2299 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2300 this->writeLabel(trueLabel, out);
2301 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2302 this->writeInstruction(SpvOpBranch, end, out);
2303 this->writeLabel(falseLabel, out);
2304 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2305 this->writeInstruction(SpvOpBranch, end, out);
2306 this->writeLabel(end, out);
2307 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002308 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002309 return result;
2310}
2311
ethannicholasd598f792016-07-25 10:08:54 -07002312std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
Ethan Nicholas024301a2017-11-10 13:49:18 -05002313 if (type.isInteger()) {
Kevin Lubickf2030782018-06-19 12:04:18 +00002314 return std::unique_ptr<Expression>(new IntLiteral(context, -1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002315 }
Ethan Nicholas024301a2017-11-10 13:49:18 -05002316 else if (type.isFloat()) {
Kevin Lubickf2030782018-06-19 12:04:18 +00002317 return std::unique_ptr<Expression>(new FloatLiteral(context, -1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002318 } else {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002319 ABORT("math is unsupported on type '%s'", type.name().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002320 }
2321}
2322
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002323SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002324 if (p.fOperator == Token::MINUS) {
2325 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002326 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002327 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002328 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002329 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002330 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002331 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2332 } else {
2333 ABORT("unsupported prefix expression %s", p.description().c_str());
2334 };
2335 return result;
2336 }
2337 switch (p.fOperator) {
2338 case Token::PLUS:
2339 return this->writeExpression(*p.fOperand, out);
2340 case Token::PLUSPLUS: {
2341 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002342 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002343 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2344 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002345 out);
2346 lv->store(result, out);
2347 return result;
2348 }
2349 case Token::MINUSMINUS: {
2350 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002351 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002352 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2353 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002354 out);
2355 lv->store(result, out);
2356 return result;
2357 }
ethannicholas5961bc92016-10-12 06:39:56 -07002358 case Token::LOGICALNOT: {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002359 SkASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002360 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002361 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002362 this->writeExpression(*p.fOperand, out), out);
2363 return result;
2364 }
ethannicholas5961bc92016-10-12 06:39:56 -07002365 case Token::BITWISENOT: {
2366 SpvId result = this->nextId();
2367 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2368 this->writeExpression(*p.fOperand, out), out);
2369 return result;
2370 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002371 default:
2372 ABORT("unsupported prefix expression: %s", p.description().c_str());
2373 }
2374}
2375
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002376SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002377 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2378 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002379 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002380 switch (p.fOperator) {
2381 case Token::PLUSPLUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002382 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002383 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2384 lv->store(temp, out);
2385 return result;
2386 }
2387 case Token::MINUSMINUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002388 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002389 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2390 lv->store(temp, out);
2391 return result;
2392 }
2393 default:
2394 ABORT("unsupported postfix expression %s", p.description().c_str());
2395 }
2396}
2397
ethannicholasf789b382016-08-03 12:43:36 -07002398SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002399 if (b.fValue) {
2400 if (fBoolTrue == 0) {
2401 fBoolTrue = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002402 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002403 fConstantBuffer);
2404 }
2405 return fBoolTrue;
2406 } else {
2407 if (fBoolFalse == 0) {
2408 fBoolFalse = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002409 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002410 fConstantBuffer);
2411 }
2412 return fBoolFalse;
2413 }
2414}
2415
ethannicholasf789b382016-08-03 12:43:36 -07002416SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholasd598f792016-07-25 10:08:54 -07002417 if (i.fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002418 auto entry = fIntConstants.find(i.fValue);
2419 if (entry == fIntConstants.end()) {
2420 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002421 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002422 fConstantBuffer);
2423 fIntConstants[i.fValue] = result;
2424 return result;
2425 }
2426 return entry->second;
2427 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002428 SkASSERT(i.fType == *fContext.fUInt_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002429 auto entry = fUIntConstants.find(i.fValue);
2430 if (entry == fUIntConstants.end()) {
2431 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002432 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002433 fConstantBuffer);
2434 fUIntConstants[i.fValue] = result;
2435 return result;
2436 }
2437 return entry->second;
2438 }
2439}
2440
ethannicholasf789b382016-08-03 12:43:36 -07002441SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002442 if (f.fType == *fContext.fFloat_Type || f.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002443 float value = (float) f.fValue;
2444 auto entry = fFloatConstants.find(value);
2445 if (entry == fFloatConstants.end()) {
2446 SpvId result = this->nextId();
2447 uint32_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002448 SkASSERT(sizeof(bits) == sizeof(value));
ethannicholasb3058bd2016-07-01 08:22:01 -07002449 memcpy(&bits, &value, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002450 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
ethannicholasb3058bd2016-07-01 08:22:01 -07002451 fConstantBuffer);
2452 fFloatConstants[value] = result;
2453 return result;
2454 }
2455 return entry->second;
2456 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002457 SkASSERT(f.fType == *fContext.fDouble_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002458 auto entry = fDoubleConstants.find(f.fValue);
2459 if (entry == fDoubleConstants.end()) {
2460 SpvId result = this->nextId();
2461 uint64_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002462 SkASSERT(sizeof(bits) == sizeof(f.fValue));
ethannicholasb3058bd2016-07-01 08:22:01 -07002463 memcpy(&bits, &f.fValue, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002464 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002465 bits & 0xffffffff, bits >> 32, fConstantBuffer);
2466 fDoubleConstants[f.fValue] = result;
2467 return result;
2468 }
2469 return entry->second;
2470 }
2471}
2472
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002473SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002474 SpvId result = fFunctionMap[&f];
Greg Daniel64773e62016-11-22 09:44:03 -05002475 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002476 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002477 this->writeInstruction(SpvOpName, result, f.fName, fNameBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002478 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002479 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002480 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002481 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002482 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002483 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2484 }
2485 return result;
2486}
2487
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002488SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2489 fVariableBuffer.reset();
ethannicholasb3058bd2016-07-01 08:22:01 -07002490 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2491 this->writeLabel(this->nextId(), out);
ethannicholasd598f792016-07-25 10:08:54 -07002492 if (f.fDeclaration.fName == "main") {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002493 write_stringstream(fGlobalInitializersBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002494 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002495 StringStream bodyBuffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04002496 this->writeBlock((Block&) *f.fBody, bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002497 write_stringstream(fVariableBuffer, out);
2498 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002499 if (fCurrentBlock) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002500 if (f.fDeclaration.fReturnType == *fContext.fVoid_Type) {
2501 this->writeInstruction(SpvOpReturn, out);
2502 } else {
2503 this->writeInstruction(SpvOpUnreachable, out);
2504 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002505 }
2506 this->writeInstruction(SpvOpFunctionEnd, out);
2507 return result;
2508}
2509
2510void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2511 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002512 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002513 fDecorationBuffer);
2514 }
2515 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002516 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002517 fDecorationBuffer);
2518 }
2519 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002520 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002521 fDecorationBuffer);
2522 }
2523 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002524 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002525 fDecorationBuffer);
2526 }
Greg Daniel64773e62016-11-22 09:44:03 -05002527 if (layout.fInputAttachmentIndex >= 0) {
2528 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2529 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002530 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002531 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002532 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Ethan Nicholas16c11962018-03-16 12:20:54 -04002533 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002534 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002535 fDecorationBuffer);
2536 }
2537}
2538
2539void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2540 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002541 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002542 layout.fLocation, fDecorationBuffer);
2543 }
2544 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002545 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002546 layout.fBinding, fDecorationBuffer);
2547 }
2548 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002549 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002550 layout.fIndex, fDecorationBuffer);
2551 }
2552 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002553 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002554 layout.fSet, fDecorationBuffer);
2555 }
Greg Daniel64773e62016-11-22 09:44:03 -05002556 if (layout.fInputAttachmentIndex >= 0) {
2557 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2558 layout.fInputAttachmentIndex, fDecorationBuffer);
2559 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002560 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002561 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002562 layout.fBuiltin, fDecorationBuffer);
2563 }
2564}
2565
Ethan Nicholas81d15112018-07-13 12:48:50 -04002566static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2567 switch (m.fLayout.fPrimitive) {
2568 case Layout::kPoints_Primitive:
2569 *outSkInCount = 1;
2570 break;
2571 case Layout::kLines_Primitive:
2572 *outSkInCount = 2;
2573 break;
2574 case Layout::kLinesAdjacency_Primitive:
2575 *outSkInCount = 4;
2576 break;
2577 case Layout::kTriangles_Primitive:
2578 *outSkInCount = 3;
2579 break;
2580 case Layout::kTrianglesAdjacency_Primitive:
2581 *outSkInCount = 6;
2582 break;
2583 default:
2584 return;
2585 }
2586}
2587
ethannicholasf789b382016-08-03 12:43:36 -07002588SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas361941e2017-05-30 15:41:07 -04002589 bool isBuffer = (0 != (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag));
Ethan Nicholas39204fd2017-11-27 13:12:30 -05002590 bool pushConstant = (0 != (intf.fVariable.fModifiers.fLayout.fFlags &
2591 Layout::kPushConstant_Flag));
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002592 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2593 MemoryLayout(MemoryLayout::k430_Standard) :
2594 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002595 SpvId result = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002596 const Type* type = &intf.fVariable.fType;
2597 if (fProgram.fInputs.fRTHeight) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002598 SkASSERT(fRTHeightStructId == (SpvId) -1);
2599 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002600 std::vector<Type::Field> fields = type->fields();
2601 fRTHeightStructId = result;
2602 fRTHeightFieldIndex = fields.size();
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002603 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
2604 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002605 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002606 SpvId typeId;
2607 if (intf.fVariable.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2608 for (const auto& e : fProgram) {
2609 if (e.fKind == ProgramElement::kModifiers_Kind) {
2610 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholas81d15112018-07-13 12:48:50 -04002611 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002612 }
2613 }
2614 typeId = this->getType(Type("sk_in", Type::kArray_Kind, intf.fVariable.fType.componentType(),
2615 fSkInCount), memoryLayout);
2616 } else {
2617 typeId = this->getType(*type, memoryLayout);
2618 }
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002619 if (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag) {
2620 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
2621 } else {
2622 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
2623 }
ethannicholasd598f792016-07-25 10:08:54 -07002624 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002625 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002626 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002627 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002628 Layout layout = intf.fVariable.fModifiers.fLayout;
2629 if (intf.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
2630 layout.fSet = 0;
2631 }
2632 this->writeLayout(layout, result);
ethannicholasd598f792016-07-25 10:08:54 -07002633 fVariableMap[&intf.fVariable] = result;
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002634 if (fProgram.fInputs.fRTHeight) {
2635 delete type;
2636 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002637 return result;
2638}
2639
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002640void SPIRVCodeGenerator::writePrecisionModifier(const Modifiers& modifiers, SpvId id) {
2641 if ((modifiers.fFlags & Modifiers::kLowp_Flag) |
2642 (modifiers.fFlags & Modifiers::kMediump_Flag)) {
2643 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2644 }
2645}
2646
ethannicholas5961bc92016-10-12 06:39:56 -07002647#define BUILTIN_IGNORE 9999
Greg Daniel64773e62016-11-22 09:44:03 -05002648void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002649 OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002650 for (size_t i = 0; i < decl.fVars.size(); i++) {
2651 if (decl.fVars[i]->fKind == Statement::kNop_Kind) {
2652 continue;
2653 }
2654 const VarDeclaration& varDecl = (VarDeclaration&) *decl.fVars[i];
2655 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002656 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2657 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002658 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002659 Modifiers::kWriteOnly_Flag |
2660 Modifiers::kCoherent_Flag |
2661 Modifiers::kVolatile_Flag |
2662 Modifiers::kRestrict_Flag)));
ethannicholas5961bc92016-10-12 06:39:56 -07002663 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2664 continue;
2665 }
2666 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2667 kind != Program::kFragment_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002668 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
ethannicholas5961bc92016-10-12 06:39:56 -07002669 continue;
2670 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05002671 if (!var->fReadCount && !var->fWriteCount &&
ethannicholas14fe8cc2016-09-07 13:37:16 -07002672 !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
2673 Modifiers::kOut_Flag |
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002674 Modifiers::kUniform_Flag |
2675 Modifiers::kBuffer_Flag))) {
ethannicholasd598f792016-07-25 10:08:54 -07002676 // variable is dead and not an input / output var (the Vulkan debug layers complain if
2677 // we elide an interface var, even if it's dead)
ethannicholasb3058bd2016-07-01 08:22:01 -07002678 continue;
2679 }
2680 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002681 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002682 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002683 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002684 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002685 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
2686 if (var->fType.kind() == Type::kSampler_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002687 storageClass = SpvStorageClassUniformConstant;
2688 } else {
2689 storageClass = SpvStorageClassUniform;
2690 }
2691 } else {
2692 storageClass = SpvStorageClassPrivate;
2693 }
2694 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002695 fVariableMap[var] = id;
Ethan Nicholas5226b772018-05-03 16:20:41 -04002696 SpvId type;
2697 if (var->fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2698 type = this->getPointerType(Type("sk_in", Type::kArray_Kind,
2699 var->fType.componentType(), fSkInCount),
2700 storageClass);
2701 } else {
2702 type = this->getPointerType(var->fType, storageClass);
2703 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002704 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002705 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002706 this->writePrecisionModifier(var->fModifiers, id);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002707 if (varDecl.fValue) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002708 SkASSERT(!fCurrentBlock);
ethannicholasf789b382016-08-03 12:43:36 -07002709 fCurrentBlock = -1;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002710 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002711 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002712 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002713 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002714 this->writeLayout(var->fModifiers.fLayout, id);
Ethan Nicholas45b0f152017-07-24 14:36:40 -04002715 if (var->fModifiers.fFlags & Modifiers::kFlat_Flag) {
2716 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2717 }
2718 if (var->fModifiers.fFlags & Modifiers::kNoPerspective_Flag) {
2719 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2720 fDecorationBuffer);
2721 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002722 }
2723}
2724
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002725void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002726 for (const auto& stmt : decl.fVars) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002727 SkASSERT(stmt->fKind == Statement::kVarDeclaration_Kind);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002728 VarDeclaration& varDecl = (VarDeclaration&) *stmt;
2729 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002730 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2731 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002732 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002733 Modifiers::kWriteOnly_Flag |
2734 Modifiers::kCoherent_Flag |
2735 Modifiers::kVolatile_Flag |
2736 Modifiers::kRestrict_Flag)));
ethannicholasb3058bd2016-07-01 08:22:01 -07002737 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002738 fVariableMap[var] = id;
2739 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002740 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002741 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002742 if (varDecl.fValue) {
2743 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002744 this->writeInstruction(SpvOpStore, id, value, out);
2745 }
2746 }
2747}
2748
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002749void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002750 switch (s.fKind) {
Ethan Nicholascb670962017-04-20 19:31:52 -04002751 case Statement::kNop_Kind:
2752 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002753 case Statement::kBlock_Kind:
2754 this->writeBlock((Block&) s, out);
2755 break;
2756 case Statement::kExpression_Kind:
2757 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2758 break;
Greg Daniel64773e62016-11-22 09:44:03 -05002759 case Statement::kReturn_Kind:
ethannicholasb3058bd2016-07-01 08:22:01 -07002760 this->writeReturnStatement((ReturnStatement&) s, out);
2761 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002762 case Statement::kVarDeclarations_Kind:
2763 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002764 break;
2765 case Statement::kIf_Kind:
2766 this->writeIfStatement((IfStatement&) s, out);
2767 break;
2768 case Statement::kFor_Kind:
2769 this->writeForStatement((ForStatement&) s, out);
2770 break;
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002771 case Statement::kWhile_Kind:
2772 this->writeWhileStatement((WhileStatement&) s, out);
2773 break;
2774 case Statement::kDo_Kind:
2775 this->writeDoStatement((DoStatement&) s, out);
2776 break;
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002777 case Statement::kSwitch_Kind:
2778 this->writeSwitchStatement((SwitchStatement&) s, out);
2779 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002780 case Statement::kBreak_Kind:
2781 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2782 break;
2783 case Statement::kContinue_Kind:
2784 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2785 break;
2786 case Statement::kDiscard_Kind:
2787 this->writeInstruction(SpvOpKill, out);
2788 break;
2789 default:
2790 ABORT("unsupported statement: %s", s.description().c_str());
2791 }
2792}
2793
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002794void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002795 for (size_t i = 0; i < b.fStatements.size(); i++) {
2796 this->writeStatement(*b.fStatements[i], out);
2797 }
2798}
2799
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002800void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002801 SpvId test = this->writeExpression(*stmt.fTest, out);
2802 SpvId ifTrue = this->nextId();
2803 SpvId ifFalse = this->nextId();
2804 if (stmt.fIfFalse) {
2805 SpvId end = this->nextId();
2806 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2807 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2808 this->writeLabel(ifTrue, out);
2809 this->writeStatement(*stmt.fIfTrue, out);
2810 if (fCurrentBlock) {
2811 this->writeInstruction(SpvOpBranch, end, out);
2812 }
2813 this->writeLabel(ifFalse, out);
2814 this->writeStatement(*stmt.fIfFalse, out);
2815 if (fCurrentBlock) {
2816 this->writeInstruction(SpvOpBranch, end, out);
2817 }
2818 this->writeLabel(end, out);
2819 } else {
2820 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2821 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2822 this->writeLabel(ifTrue, out);
2823 this->writeStatement(*stmt.fIfTrue, out);
2824 if (fCurrentBlock) {
2825 this->writeInstruction(SpvOpBranch, ifFalse, out);
2826 }
2827 this->writeLabel(ifFalse, out);
2828 }
2829}
2830
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002831void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002832 if (f.fInitializer) {
2833 this->writeStatement(*f.fInitializer, out);
2834 }
2835 SpvId header = this->nextId();
2836 SpvId start = this->nextId();
2837 SpvId body = this->nextId();
2838 SpvId next = this->nextId();
2839 fContinueTarget.push(next);
2840 SpvId end = this->nextId();
2841 fBreakTarget.push(end);
2842 this->writeInstruction(SpvOpBranch, header, out);
2843 this->writeLabel(header, out);
2844 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002845 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002846 this->writeLabel(start, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002847 if (f.fTest) {
2848 SpvId test = this->writeExpression(*f.fTest, out);
2849 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2850 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002851 this->writeLabel(body, out);
2852 this->writeStatement(*f.fStatement, out);
2853 if (fCurrentBlock) {
2854 this->writeInstruction(SpvOpBranch, next, out);
2855 }
2856 this->writeLabel(next, out);
2857 if (f.fNext) {
2858 this->writeExpression(*f.fNext, out);
2859 }
2860 this->writeInstruction(SpvOpBranch, header, out);
2861 this->writeLabel(end, out);
2862 fBreakTarget.pop();
2863 fContinueTarget.pop();
2864}
2865
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002866void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002867 // We believe the while loop code below will work, but Skia doesn't actually use them and
2868 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2869 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2870 // message, simply remove the error call below to see whether our while loop support actually
2871 // works.
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002872 fErrors.error(w.fOffset, "internal error: while loop support has been disabled in SPIR-V, "
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002873 "see SkSLSPIRVCodeGenerator.cpp for details");
2874
2875 SpvId header = this->nextId();
2876 SpvId start = this->nextId();
2877 SpvId body = this->nextId();
2878 fContinueTarget.push(start);
2879 SpvId end = this->nextId();
2880 fBreakTarget.push(end);
2881 this->writeInstruction(SpvOpBranch, header, out);
2882 this->writeLabel(header, out);
2883 this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out);
2884 this->writeInstruction(SpvOpBranch, start, out);
2885 this->writeLabel(start, out);
2886 SpvId test = this->writeExpression(*w.fTest, out);
2887 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2888 this->writeLabel(body, out);
2889 this->writeStatement(*w.fStatement, out);
2890 if (fCurrentBlock) {
2891 this->writeInstruction(SpvOpBranch, start, out);
2892 }
2893 this->writeLabel(end, out);
2894 fBreakTarget.pop();
2895 fContinueTarget.pop();
2896}
2897
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002898void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002899 // We believe the do loop code below will work, but Skia doesn't actually use them and
2900 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2901 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2902 // message, simply remove the error call below to see whether our do loop support actually
2903 // works.
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002904 fErrors.error(d.fOffset, "internal error: do loop support has been disabled in SPIR-V, see "
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002905 "SkSLSPIRVCodeGenerator.cpp for details");
2906
2907 SpvId header = this->nextId();
2908 SpvId start = this->nextId();
2909 SpvId next = this->nextId();
2910 fContinueTarget.push(next);
2911 SpvId end = this->nextId();
2912 fBreakTarget.push(end);
2913 this->writeInstruction(SpvOpBranch, header, out);
2914 this->writeLabel(header, out);
2915 this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out);
2916 this->writeInstruction(SpvOpBranch, start, out);
2917 this->writeLabel(start, out);
2918 this->writeStatement(*d.fStatement, out);
2919 if (fCurrentBlock) {
2920 this->writeInstruction(SpvOpBranch, next, out);
2921 }
2922 this->writeLabel(next, out);
2923 SpvId test = this->writeExpression(*d.fTest, out);
2924 this->writeInstruction(SpvOpBranchConditional, test, start, end, out);
2925 this->writeLabel(end, out);
2926 fBreakTarget.pop();
2927 fContinueTarget.pop();
2928}
2929
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002930void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
2931 SpvId value = this->writeExpression(*s.fValue, out);
2932 std::vector<SpvId> labels;
2933 SpvId end = this->nextId();
2934 SpvId defaultLabel = end;
2935 fBreakTarget.push(end);
2936 int size = 3;
2937 for (const auto& c : s.fCases) {
2938 SpvId label = this->nextId();
2939 labels.push_back(label);
2940 if (c->fValue) {
2941 size += 2;
2942 } else {
2943 defaultLabel = label;
2944 }
2945 }
2946 labels.push_back(end);
2947 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2948 this->writeOpCode(SpvOpSwitch, size, out);
2949 this->writeWord(value, out);
2950 this->writeWord(defaultLabel, out);
2951 for (size_t i = 0; i < s.fCases.size(); ++i) {
2952 if (!s.fCases[i]->fValue) {
2953 continue;
2954 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002955 SkASSERT(s.fCases[i]->fValue->fKind == Expression::kIntLiteral_Kind);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002956 this->writeWord(((IntLiteral&) *s.fCases[i]->fValue).fValue, out);
2957 this->writeWord(labels[i], out);
2958 }
2959 for (size_t i = 0; i < s.fCases.size(); ++i) {
2960 this->writeLabel(labels[i], out);
2961 for (const auto& stmt : s.fCases[i]->fStatements) {
2962 this->writeStatement(*stmt, out);
2963 }
2964 if (fCurrentBlock) {
2965 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
2966 }
2967 }
2968 this->writeLabel(end, out);
2969 fBreakTarget.pop();
2970}
2971
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002972void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002973 if (r.fExpression) {
Greg Daniel64773e62016-11-22 09:44:03 -05002974 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
ethannicholasb3058bd2016-07-01 08:22:01 -07002975 out);
2976 } else {
2977 this->writeInstruction(SpvOpReturn, out);
2978 }
2979}
2980
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002981void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002982 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002983 int invocations = 1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04002984 for (const auto& e : fProgram) {
2985 if (e.fKind == ProgramElement::kModifiers_Kind) {
2986 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002987 if (m.fFlags & Modifiers::kIn_Flag) {
2988 if (m.fLayout.fInvocations != -1) {
2989 invocations = m.fLayout.fInvocations;
2990 }
2991 SpvId input;
2992 switch (m.fLayout.fPrimitive) {
2993 case Layout::kPoints_Primitive:
2994 input = SpvExecutionModeInputPoints;
2995 break;
2996 case Layout::kLines_Primitive:
2997 input = SpvExecutionModeInputLines;
2998 break;
2999 case Layout::kLinesAdjacency_Primitive:
3000 input = SpvExecutionModeInputLinesAdjacency;
3001 break;
3002 case Layout::kTriangles_Primitive:
3003 input = SpvExecutionModeTriangles;
3004 break;
3005 case Layout::kTrianglesAdjacency_Primitive:
3006 input = SpvExecutionModeInputTrianglesAdjacency;
3007 break;
3008 default:
3009 input = 0;
3010 break;
3011 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003012 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003013 if (input) {
3014 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3015 }
3016 } else if (m.fFlags & Modifiers::kOut_Flag) {
3017 SpvId output;
3018 switch (m.fLayout.fPrimitive) {
3019 case Layout::kPoints_Primitive:
3020 output = SpvExecutionModeOutputPoints;
3021 break;
3022 case Layout::kLineStrip_Primitive:
3023 output = SpvExecutionModeOutputLineStrip;
3024 break;
3025 case Layout::kTriangleStrip_Primitive:
3026 output = SpvExecutionModeOutputTriangleStrip;
3027 break;
3028 default:
3029 output = 0;
3030 break;
3031 }
3032 if (output) {
3033 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3034 }
3035 if (m.fLayout.fMaxVertices != -1) {
3036 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3037 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3038 out);
3039 }
3040 }
3041 }
3042 }
3043 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3044 invocations, out);
3045}
3046
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003047void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003048 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003049 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003050 std::set<SpvId> interfaceVars;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003051 // assign IDs to functions, determine sk_in size
3052 int skInSize = -1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003053 for (const auto& e : program) {
3054 switch (e.fKind) {
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003055 case ProgramElement::kFunction_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003056 FunctionDefinition& f = (FunctionDefinition&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003057 fFunctionMap[&f.fDeclaration] = this->nextId();
3058 break;
3059 }
3060 case ProgramElement::kModifiers_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003061 Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003062 if (m.fFlags & Modifiers::kIn_Flag) {
3063 switch (m.fLayout.fPrimitive) {
3064 case Layout::kPoints_Primitive: // break
3065 case Layout::kLines_Primitive:
3066 skInSize = 1;
3067 break;
3068 case Layout::kLinesAdjacency_Primitive: // break
3069 skInSize = 2;
3070 break;
3071 case Layout::kTriangles_Primitive: // break
3072 case Layout::kTrianglesAdjacency_Primitive:
3073 skInSize = 3;
3074 break;
3075 default:
3076 break;
3077 }
3078 }
3079 break;
3080 }
3081 default:
3082 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003083 }
3084 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003085 for (const auto& e : program) {
3086 if (e.fKind == ProgramElement::kInterfaceBlock_Kind) {
3087 InterfaceBlock& intf = (InterfaceBlock&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003088 if (SK_IN_BUILTIN == intf.fVariable.fModifiers.fLayout.fBuiltin) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003089 SkASSERT(skInSize != -1);
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003090 intf.fSizes.emplace_back(new IntLiteral(fContext, -1, skInSize));
3091 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003092 SpvId id = this->writeInterfaceBlock(intf);
Ethan Nicholas16c11962018-03-16 12:20:54 -04003093 if (((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
3094 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) &&
3095 intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003096 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003097 }
3098 }
3099 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003100 for (const auto& e : program) {
3101 if (e.fKind == ProgramElement::kVar_Kind) {
3102 this->writeGlobalVars(program.fKind, ((VarDeclarations&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003103 }
3104 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003105 for (const auto& e : program) {
3106 if (e.fKind == ProgramElement::kFunction_Kind) {
3107 this->writeFunction(((FunctionDefinition&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003108 }
3109 }
ethannicholasd598f792016-07-25 10:08:54 -07003110 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003111 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07003112 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003113 main = entry.first;
3114 }
3115 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003116 SkASSERT(main);
ethannicholasb3058bd2016-07-01 08:22:01 -07003117 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003118 const Variable* var = entry.first;
Ethan Nicholas81d15112018-07-13 12:48:50 -04003119 int builtin = var->fModifiers.fLayout.fBuiltin;
Greg Daniel64773e62016-11-22 09:44:03 -05003120 if (var->fStorage == Variable::kGlobal_Storage &&
Ethan Nicholas16c11962018-03-16 12:20:54 -04003121 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
Ethan Nicholas81d15112018-07-13 12:48:50 -04003122 (var->fModifiers.fFlags & Modifiers::kOut_Flag)) &&
3123 builtin != SK_OUT_BUILTIN &&
3124 builtin != SK_INVOCATIONID_BUILTIN) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003125 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003126 }
3127 }
3128 this->writeCapabilities(out);
3129 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3130 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003131 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->fName.fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003132 (int32_t) interfaceVars.size(), out);
3133 switch (program.fKind) {
3134 case Program::kVertex_Kind:
3135 this->writeWord(SpvExecutionModelVertex, out);
3136 break;
3137 case Program::kFragment_Kind:
3138 this->writeWord(SpvExecutionModelFragment, out);
3139 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003140 case Program::kGeometry_Kind:
3141 this->writeWord(SpvExecutionModelGeometry, out);
3142 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003143 default:
3144 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003145 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003146 SpvId entryPoint = fFunctionMap[main];
3147 this->writeWord(entryPoint, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003148 this->writeString(main->fName.fChars, main->fName.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003149 for (int var : interfaceVars) {
3150 this->writeWord(var, out);
3151 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003152 if (program.fKind == Program::kGeometry_Kind) {
3153 this->writeGeometryShaderExecutionMode(entryPoint, out);
3154 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003155 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003156 this->writeInstruction(SpvOpExecutionMode,
3157 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003158 SpvExecutionModeOriginUpperLeft,
3159 out);
3160 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003161 for (const auto& e : program) {
3162 if (e.fKind == ProgramElement::kExtension_Kind) {
3163 this->writeInstruction(SpvOpSourceExtension, ((Extension&) e).fName.c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003164 }
3165 }
Greg Daniel64773e62016-11-22 09:44:03 -05003166
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003167 write_stringstream(fExtraGlobalsBuffer, out);
3168 write_stringstream(fNameBuffer, out);
3169 write_stringstream(fDecorationBuffer, out);
3170 write_stringstream(fConstantBuffer, out);
3171 write_stringstream(fExternalFunctionsBuffer, out);
3172 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003173}
3174
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003175bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003176 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003177 this->writeWord(SpvMagicNumber, *fOut);
3178 this->writeWord(SpvVersion, *fOut);
3179 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003180 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003181 this->writeInstructions(fProgram, buffer);
3182 this->writeWord(fIdCount, *fOut);
3183 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003184 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003185 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003186}
3187
3188}