blob: 185f52f4ac9064c8e976bd2cd33e398970a0e1ae [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Ethan Nicholasbcf35f82017-03-30 18:42:48 +00007
Ethan Nicholas0df1b042017-03-31 13:56:23 -04008#include "SkSLSPIRVCodeGenerator.h"
Ethan Nicholas9bd301d2017-03-31 16:04:34 +00009
ethannicholasb3058bd2016-07-01 08:22:01 -070010#include "GLSL.std.450.h"
11
12#include "ir/SkSLExpressionStatement.h"
13#include "ir/SkSLExtension.h"
14#include "ir/SkSLIndexExpression.h"
15#include "ir/SkSLVariableReference.h"
ethannicholas5961bc92016-10-12 06:39:56 -070016#include "SkSLCompiler.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070017
18namespace SkSL {
19
ethannicholasb3058bd2016-07-01 08:22:01 -070020static const int32_t SKSL_MAGIC = 0x0; // FIXME: we should probably register a magic number
21
22void SPIRVCodeGenerator::setupIntrinsics() {
23#define ALL_GLSL(x) std::make_tuple(kGLSL_STD_450_IntrinsicKind, GLSLstd450 ## x, GLSLstd450 ## x, \
24 GLSLstd450 ## x, GLSLstd450 ## x)
25#define BY_TYPE_GLSL(ifFloat, ifInt, ifUInt) std::make_tuple(kGLSL_STD_450_IntrinsicKind, \
26 GLSLstd450 ## ifFloat, \
27 GLSLstd450 ## ifInt, \
28 GLSLstd450 ## ifUInt, \
29 SpvOpUndef)
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040030#define ALL_SPIRV(x) std::make_tuple(kSPIRV_IntrinsicKind, SpvOp ## x, SpvOp ## x, SpvOp ## x, \
31 SpvOp ## x)
ethannicholasb3058bd2016-07-01 08:22:01 -070032#define SPECIAL(x) std::make_tuple(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic, \
33 k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
34 k ## x ## _SpecialIntrinsic)
Ethan Nicholas0df1b042017-03-31 13:56:23 -040035 fIntrinsicMap[String("round")] = ALL_GLSL(Round);
36 fIntrinsicMap[String("roundEven")] = ALL_GLSL(RoundEven);
37 fIntrinsicMap[String("trunc")] = ALL_GLSL(Trunc);
38 fIntrinsicMap[String("abs")] = BY_TYPE_GLSL(FAbs, SAbs, SAbs);
39 fIntrinsicMap[String("sign")] = BY_TYPE_GLSL(FSign, SSign, SSign);
40 fIntrinsicMap[String("floor")] = ALL_GLSL(Floor);
41 fIntrinsicMap[String("ceil")] = ALL_GLSL(Ceil);
42 fIntrinsicMap[String("fract")] = ALL_GLSL(Fract);
43 fIntrinsicMap[String("radians")] = ALL_GLSL(Radians);
44 fIntrinsicMap[String("degrees")] = ALL_GLSL(Degrees);
45 fIntrinsicMap[String("sin")] = ALL_GLSL(Sin);
46 fIntrinsicMap[String("cos")] = ALL_GLSL(Cos);
47 fIntrinsicMap[String("tan")] = ALL_GLSL(Tan);
48 fIntrinsicMap[String("asin")] = ALL_GLSL(Asin);
49 fIntrinsicMap[String("acos")] = ALL_GLSL(Acos);
50 fIntrinsicMap[String("atan")] = SPECIAL(Atan);
51 fIntrinsicMap[String("sinh")] = ALL_GLSL(Sinh);
52 fIntrinsicMap[String("cosh")] = ALL_GLSL(Cosh);
53 fIntrinsicMap[String("tanh")] = ALL_GLSL(Tanh);
54 fIntrinsicMap[String("asinh")] = ALL_GLSL(Asinh);
55 fIntrinsicMap[String("acosh")] = ALL_GLSL(Acosh);
56 fIntrinsicMap[String("atanh")] = ALL_GLSL(Atanh);
57 fIntrinsicMap[String("pow")] = ALL_GLSL(Pow);
58 fIntrinsicMap[String("exp")] = ALL_GLSL(Exp);
59 fIntrinsicMap[String("log")] = ALL_GLSL(Log);
60 fIntrinsicMap[String("exp2")] = ALL_GLSL(Exp2);
61 fIntrinsicMap[String("log2")] = ALL_GLSL(Log2);
62 fIntrinsicMap[String("sqrt")] = ALL_GLSL(Sqrt);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040063 fIntrinsicMap[String("inverse")] = ALL_GLSL(MatrixInverse);
64 fIntrinsicMap[String("transpose")] = ALL_SPIRV(Transpose);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040065 fIntrinsicMap[String("inversesqrt")] = ALL_GLSL(InverseSqrt);
66 fIntrinsicMap[String("determinant")] = ALL_GLSL(Determinant);
67 fIntrinsicMap[String("matrixInverse")] = ALL_GLSL(MatrixInverse);
Ethan Nicholas70a44b22017-11-30 09:09:16 -050068 fIntrinsicMap[String("mod")] = SPECIAL(Mod);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050069 fIntrinsicMap[String("min")] = SPECIAL(Min);
70 fIntrinsicMap[String("max")] = SPECIAL(Max);
71 fIntrinsicMap[String("clamp")] = SPECIAL(Clamp);
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040072 fIntrinsicMap[String("saturate")] = SPECIAL(Saturate);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040073 fIntrinsicMap[String("dot")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
Ethan Nicholas0187ae62017-05-03 11:03:44 -040074 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050075 fIntrinsicMap[String("mix")] = SPECIAL(Mix);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040076 fIntrinsicMap[String("step")] = ALL_GLSL(Step);
77 fIntrinsicMap[String("smoothstep")] = ALL_GLSL(SmoothStep);
78 fIntrinsicMap[String("fma")] = ALL_GLSL(Fma);
79 fIntrinsicMap[String("frexp")] = ALL_GLSL(Frexp);
80 fIntrinsicMap[String("ldexp")] = ALL_GLSL(Ldexp);
ethannicholasb3058bd2016-07-01 08:22:01 -070081
Ethan Nicholas0df1b042017-03-31 13:56:23 -040082#define PACK(type) fIntrinsicMap[String("pack" #type)] = ALL_GLSL(Pack ## type); \
83 fIntrinsicMap[String("unpack" #type)] = ALL_GLSL(Unpack ## type)
ethannicholasb3058bd2016-07-01 08:22:01 -070084 PACK(Snorm4x8);
85 PACK(Unorm4x8);
86 PACK(Snorm2x16);
87 PACK(Unorm2x16);
88 PACK(Half2x16);
89 PACK(Double2x32);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040090 fIntrinsicMap[String("length")] = ALL_GLSL(Length);
91 fIntrinsicMap[String("distance")] = ALL_GLSL(Distance);
92 fIntrinsicMap[String("cross")] = ALL_GLSL(Cross);
93 fIntrinsicMap[String("normalize")] = ALL_GLSL(Normalize);
94 fIntrinsicMap[String("faceForward")] = ALL_GLSL(FaceForward);
95 fIntrinsicMap[String("reflect")] = ALL_GLSL(Reflect);
96 fIntrinsicMap[String("refract")] = ALL_GLSL(Refract);
97 fIntrinsicMap[String("findLSB")] = ALL_GLSL(FindILsb);
98 fIntrinsicMap[String("findMSB")] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
99 fIntrinsicMap[String("dFdx")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400100 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700101 fIntrinsicMap[String("dFdy")] = SPECIAL(DFdy);
Chris Dalton09212192018-11-13 15:07:24 -0500102 fIntrinsicMap[String("fwidth")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFwidth,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400103 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400104 fIntrinsicMap[String("texture")] = SPECIAL(Texture);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400105 fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
Greg Daniel64773e62016-11-22 09:44:03 -0500106
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400107 fIntrinsicMap[String("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400108 SpvOpUndef, SpvOpUndef, SpvOpAny);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400109 fIntrinsicMap[String("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400110 SpvOpUndef, SpvOpUndef, SpvOpAll);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400111 fIntrinsicMap[String("equal")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400112 SpvOpFOrdEqual, SpvOpIEqual,
113 SpvOpIEqual, SpvOpLogicalEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400114 fIntrinsicMap[String("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400115 SpvOpFOrdNotEqual, SpvOpINotEqual,
116 SpvOpINotEqual,
117 SpvOpLogicalNotEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400118 fIntrinsicMap[String("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500119 SpvOpFOrdLessThan, SpvOpSLessThan,
120 SpvOpULessThan, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400121 fIntrinsicMap[String("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500122 SpvOpFOrdLessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400123 SpvOpSLessThanEqual,
124 SpvOpULessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400125 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400126 fIntrinsicMap[String("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500127 SpvOpFOrdGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400128 SpvOpSGreaterThan,
129 SpvOpUGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400130 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400131 fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500132 SpvOpFOrdGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400133 SpvOpSGreaterThanEqual,
134 SpvOpUGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400135 SpvOpUndef);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400136 fIntrinsicMap[String("EmitVertex")] = ALL_SPIRV(EmitVertex);
137 fIntrinsicMap[String("EndPrimitive")] = ALL_SPIRV(EndPrimitive);
ethannicholasb3058bd2016-07-01 08:22:01 -0700138// interpolateAt* not yet supported...
139}
140
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400141void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700142 out.write((const char*) &word, sizeof(word));
ethannicholasb3058bd2016-07-01 08:22:01 -0700143}
144
ethannicholasd598f792016-07-25 10:08:54 -0700145static bool is_float(const Context& context, const Type& type) {
Ethan Nicholas0df21132018-07-10 09:37:51 -0400146 if (type.columns() > 1) {
ethannicholasd598f792016-07-25 10:08:54 -0700147 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700148 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400149 return type == *context.fFloat_Type || type == *context.fHalf_Type ||
150 type == *context.fDouble_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700151}
152
ethannicholasd598f792016-07-25 10:08:54 -0700153static bool is_signed(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700154 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700155 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700156 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400157 return type == *context.fInt_Type || type == *context.fShort_Type ||
158 type == *context.fByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700159}
160
ethannicholasd598f792016-07-25 10:08:54 -0700161static bool is_unsigned(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700162 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700163 return is_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700164 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400165 return type == *context.fUInt_Type || type == *context.fUShort_Type ||
166 type == *context.fUByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700167}
168
ethannicholasd598f792016-07-25 10:08:54 -0700169static bool is_bool(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700170 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700171 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700172 }
ethannicholasd598f792016-07-25 10:08:54 -0700173 return type == *context.fBool_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700174}
175
ethannicholasd598f792016-07-25 10:08:54 -0700176static bool is_out(const Variable& var) {
177 return (var.fModifiers.fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700178}
179
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400180void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400181 SkASSERT(opCode != SpvOpLoad || &out != &fConstantBuffer);
182 SkASSERT(opCode != SpvOpUndef);
ethannicholasb3058bd2016-07-01 08:22:01 -0700183 switch (opCode) {
184 case SpvOpReturn: // fall through
185 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700186 case SpvOpKill: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700187 case SpvOpBranch: // fall through
188 case SpvOpBranchConditional:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400189 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700190 fCurrentBlock = 0;
191 break;
192 case SpvOpConstant: // fall through
193 case SpvOpConstantTrue: // fall through
194 case SpvOpConstantFalse: // fall through
195 case SpvOpConstantComposite: // fall through
196 case SpvOpTypeVoid: // fall through
197 case SpvOpTypeInt: // fall through
198 case SpvOpTypeFloat: // fall through
199 case SpvOpTypeBool: // fall through
200 case SpvOpTypeVector: // fall through
201 case SpvOpTypeMatrix: // fall through
202 case SpvOpTypeArray: // fall through
203 case SpvOpTypePointer: // fall through
204 case SpvOpTypeFunction: // fall through
205 case SpvOpTypeRuntimeArray: // fall through
206 case SpvOpTypeStruct: // fall through
207 case SpvOpTypeImage: // fall through
208 case SpvOpTypeSampledImage: // fall through
209 case SpvOpVariable: // fall through
210 case SpvOpFunction: // fall through
211 case SpvOpFunctionParameter: // fall through
212 case SpvOpFunctionEnd: // fall through
213 case SpvOpExecutionMode: // fall through
214 case SpvOpMemoryModel: // fall through
215 case SpvOpCapability: // fall through
216 case SpvOpExtInstImport: // fall through
217 case SpvOpEntryPoint: // fall through
218 case SpvOpSource: // fall through
219 case SpvOpSourceExtension: // fall through
220 case SpvOpName: // fall through
221 case SpvOpMemberName: // fall through
222 case SpvOpDecorate: // fall through
223 case SpvOpMemberDecorate:
224 break;
225 default:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400226 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700227 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700228 this->writeWord((length << 16) | opCode, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700229}
230
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400231void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700232 fCurrentBlock = label;
233 this->writeInstruction(SpvOpLabel, label, out);
234}
235
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400236void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700237 this->writeOpCode(opCode, 1, out);
238}
239
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400240void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700241 this->writeOpCode(opCode, 2, out);
242 this->writeWord(word1, out);
243}
244
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700245void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputStream& out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400246 out.write(string, length);
ethannicholasb3058bd2016-07-01 08:22:01 -0700247 switch (length % 4) {
248 case 1:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500249 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700250 // fall through
251 case 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500252 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700253 // fall through
254 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500255 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700256 break;
257 default:
258 this->writeWord(0, out);
259 }
260}
261
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700262void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out) {
263 this->writeOpCode(opCode, 1 + (string.fLength + 4) / 4, out);
264 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700265}
266
267
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700268void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400269 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700270 this->writeOpCode(opCode, 2 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700271 this->writeWord(word1, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700272 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700273}
274
Greg Daniel64773e62016-11-22 09:44:03 -0500275void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700276 StringFragment string, OutputStream& out) {
277 this->writeOpCode(opCode, 3 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700278 this->writeWord(word1, out);
279 this->writeWord(word2, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700280 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700281}
282
Greg Daniel64773e62016-11-22 09:44:03 -0500283void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400284 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700285 this->writeOpCode(opCode, 3, out);
286 this->writeWord(word1, out);
287 this->writeWord(word2, out);
288}
289
Greg Daniel64773e62016-11-22 09:44:03 -0500290void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400291 int32_t word3, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700292 this->writeOpCode(opCode, 4, out);
293 this->writeWord(word1, out);
294 this->writeWord(word2, out);
295 this->writeWord(word3, out);
296}
297
Greg Daniel64773e62016-11-22 09:44:03 -0500298void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400299 int32_t word3, int32_t word4, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700300 this->writeOpCode(opCode, 5, out);
301 this->writeWord(word1, out);
302 this->writeWord(word2, out);
303 this->writeWord(word3, out);
304 this->writeWord(word4, out);
305}
306
Greg Daniel64773e62016-11-22 09:44:03 -0500307void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
308 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400309 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700310 this->writeOpCode(opCode, 6, out);
311 this->writeWord(word1, out);
312 this->writeWord(word2, out);
313 this->writeWord(word3, out);
314 this->writeWord(word4, out);
315 this->writeWord(word5, out);
316}
317
Greg Daniel64773e62016-11-22 09:44:03 -0500318void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700319 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400320 int32_t word6, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700321 this->writeOpCode(opCode, 7, out);
322 this->writeWord(word1, out);
323 this->writeWord(word2, out);
324 this->writeWord(word3, out);
325 this->writeWord(word4, out);
326 this->writeWord(word5, out);
327 this->writeWord(word6, out);
328}
329
Greg Daniel64773e62016-11-22 09:44:03 -0500330void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700331 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400332 int32_t word6, int32_t word7, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700333 this->writeOpCode(opCode, 8, out);
334 this->writeWord(word1, out);
335 this->writeWord(word2, out);
336 this->writeWord(word3, out);
337 this->writeWord(word4, out);
338 this->writeWord(word5, out);
339 this->writeWord(word6, out);
340 this->writeWord(word7, out);
341}
342
Greg Daniel64773e62016-11-22 09:44:03 -0500343void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700344 int32_t word3, int32_t word4, int32_t word5,
345 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400346 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700347 this->writeOpCode(opCode, 9, out);
348 this->writeWord(word1, out);
349 this->writeWord(word2, out);
350 this->writeWord(word3, out);
351 this->writeWord(word4, out);
352 this->writeWord(word5, out);
353 this->writeWord(word6, out);
354 this->writeWord(word7, out);
355 this->writeWord(word8, out);
356}
357
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400358void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700359 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
360 if (fCapabilities & bit) {
361 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
362 }
363 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400364 if (fProgram.fKind == Program::kGeometry_Kind) {
365 this->writeInstruction(SpvOpCapability, SpvCapabilityGeometry, out);
366 }
Ethan Nicholas81d15112018-07-13 12:48:50 -0400367 else {
368 this->writeInstruction(SpvOpCapability, SpvCapabilityShader, out);
369 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700370}
371
372SpvId SPIRVCodeGenerator::nextId() {
373 return fIdCount++;
374}
375
Ethan Nicholas19671772016-11-28 16:30:17 -0500376void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
377 SpvId resultId) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700378 this->writeInstruction(SpvOpName, resultId, type.name().c_str(), fNameBuffer);
379 // go ahead and write all of the field types, so we don't inadvertently write them while we're
380 // in the middle of writing the struct instruction
381 std::vector<SpvId> types;
382 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500383 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700384 }
385 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
386 this->writeWord(resultId, fConstantBuffer);
387 for (SpvId id : types) {
388 this->writeWord(id, fConstantBuffer);
389 }
390 size_t offset = 0;
391 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Ethan Nicholas151a8832019-04-16 12:07:26 -0400392 const Type::Field& field = type.fields()[i];
393 size_t size = memoryLayout.size(*field.fType);
394 size_t alignment = memoryLayout.alignment(*field.fType);
395 const Layout& fieldLayout = field.fModifiers.fLayout;
Ethan Nicholas19671772016-11-28 16:30:17 -0500396 if (fieldLayout.fOffset >= 0) {
Greg Danieldbd44c72017-01-24 15:12:12 -0500397 if (fieldLayout.fOffset < (int) offset) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700398 fErrors.error(type.fOffset,
Ethan Nicholas151a8832019-04-16 12:07:26 -0400399 "offset of field '" + field.fName + "' must be at "
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500400 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -0500401 }
402 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700403 fErrors.error(type.fOffset,
Ethan Nicholas151a8832019-04-16 12:07:26 -0400404 "offset of field '" + field.fName + "' must be a multiple"
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500405 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -0500406 }
407 offset = fieldLayout.fOffset;
408 } else {
409 size_t mod = offset % alignment;
410 if (mod) {
411 offset += alignment - mod;
412 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700413 }
Ethan Nicholas151a8832019-04-16 12:07:26 -0400414 this->writeInstruction(SpvOpMemberName, resultId, i, field.fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500415 this->writeLayout(fieldLayout, resultId, i);
Ethan Nicholas151a8832019-04-16 12:07:26 -0400416 if (field.fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -0500417 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700418 (SpvId) offset, fDecorationBuffer);
419 }
Ethan Nicholas151a8832019-04-16 12:07:26 -0400420 if (field.fType->kind() == Type::kMatrix_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -0500421 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -0700422 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500423 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Ethan Nicholas151a8832019-04-16 12:07:26 -0400424 (SpvId) memoryLayout.stride(*field.fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800425 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700426 }
Ethan Nicholas151a8832019-04-16 12:07:26 -0400427 if (!field.fType->highPrecision()) {
428 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i,
429 SpvDecorationRelaxedPrecision, fDecorationBuffer);
430 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700431 offset += size;
Ethan Nicholas151a8832019-04-16 12:07:26 -0400432 Type::Kind kind = field.fType->kind();
ethannicholasb3058bd2016-07-01 08:22:01 -0700433 if ((kind == Type::kArray_Kind || kind == Type::kStruct_Kind) && offset % alignment != 0) {
434 offset += alignment - offset % alignment;
435 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700436 }
437}
438
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400439Type SPIRVCodeGenerator::getActualType(const Type& type) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500440 if (type.isFloat()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400441 return *fContext.fFloat_Type;
442 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500443 if (type.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400444 return *fContext.fInt_Type;
445 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500446 if (type.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400447 return *fContext.fUInt_Type;
448 }
449 if (type.kind() == Type::kMatrix_Kind || type.kind() == Type::kVector_Kind) {
450 if (type.componentType() == *fContext.fHalf_Type) {
451 return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
452 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400453 if (type.componentType() == *fContext.fShort_Type ||
454 type.componentType() == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400455 return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
456 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400457 if (type.componentType() == *fContext.fUShort_Type ||
458 type.componentType() == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400459 return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
460 }
461 }
462 return type;
463}
464
ethannicholasb3058bd2016-07-01 08:22:01 -0700465SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800466 return this->getType(type, fDefaultLayout);
467}
468
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400469SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
470 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400471 String key = type.name() + to_string((int) layout.fStd);
ethannicholas8ac838d2016-11-22 08:39:36 -0800472 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700473 if (entry == fTypeMap.end()) {
474 SpvId result = this->nextId();
475 switch (type.kind()) {
476 case Type::kScalar_Kind:
ethannicholasd598f792016-07-25 10:08:54 -0700477 if (type == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700478 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500479 } else if (type == *fContext.fInt_Type || type == *fContext.fShort_Type ||
480 type == *fContext.fIntLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700481 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500482 } else if (type == *fContext.fUInt_Type || type == *fContext.fUShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700483 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500484 } else if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type ||
485 type == *fContext.fFloatLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700486 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -0700487 } else if (type == *fContext.fDouble_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700488 this->writeInstruction(SpvOpTypeFloat, result, 64, fConstantBuffer);
489 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400490 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700491 }
492 break;
493 case Type::kVector_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500494 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800495 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700496 type.columns(), fConstantBuffer);
497 break;
498 case Type::kMatrix_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500499 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800500 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700501 type.columns(), fConstantBuffer);
502 break;
503 case Type::kStruct_Kind:
ethannicholas8ac838d2016-11-22 08:39:36 -0800504 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700505 break;
506 case Type::kArray_Kind: {
507 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700508 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500509 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800510 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700511 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500512 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400513 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800514 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700515 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400516 SkASSERT(false); // we shouldn't have any runtime-sized arrays right now
Greg Daniel64773e62016-11-22 09:44:03 -0500517 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800518 this->getType(type.componentType(), layout),
519 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400520 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
521 (int32_t) layout.stride(type),
522 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700523 }
524 break;
525 }
526 case Type::kSampler_Kind: {
Greg Daniel64773e62016-11-22 09:44:03 -0500527 SpvId image = result;
528 if (SpvDimSubpassData != type.dimensions()) {
529 image = this->nextId();
530 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400531 if (SpvDimBuffer == type.dimensions()) {
532 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
533 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800534 this->writeInstruction(SpvOpTypeImage, image,
535 this->getType(*fContext.fFloat_Type, layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700536 type.dimensions(), type.isDepth(), type.isArrayed(),
Greg Daniel64773e62016-11-22 09:44:03 -0500537 type.isMultisampled(), type.isSampled() ? 1 : 2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700538 SpvImageFormatUnknown, fConstantBuffer);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400539 fImageTypeMap[key] = image;
Greg Daniel64773e62016-11-22 09:44:03 -0500540 if (SpvDimSubpassData != type.dimensions()) {
541 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
542 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700543 break;
544 }
545 default:
ethannicholasd598f792016-07-25 10:08:54 -0700546 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700547 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
548 } else {
549 ABORT("invalid type: %s", type.description().c_str());
550 }
551 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800552 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700553 return result;
554 }
555 return entry->second;
556}
557
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400558SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400559 SkASSERT(type.kind() == Type::kSampler_Kind);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400560 this->getType(type);
561 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400562 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400563 return fImageTypeMap[key];
564}
565
ethannicholasd598f792016-07-25 10:08:54 -0700566SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400567 String key = function.fReturnType.description() + "(";
568 String separator;
ethannicholasd598f792016-07-25 10:08:54 -0700569 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700570 key += separator;
571 separator = ", ";
ethannicholasd598f792016-07-25 10:08:54 -0700572 key += function.fParameters[i]->fType.description();
ethannicholasb3058bd2016-07-01 08:22:01 -0700573 }
574 key += ")";
575 auto entry = fTypeMap.find(key);
576 if (entry == fTypeMap.end()) {
577 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -0700578 int32_t length = 3 + (int32_t) function.fParameters.size();
579 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700580 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -0700581 for (size_t i = 0; i < function.fParameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500582 // glslang seems to treat all function arguments as pointers whether they need to be or
583 // not. I was initially puzzled by this until I ran bizarre failures with certain
584 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700585 // failure case:
586 //
587 // void sphere(float x) {
588 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500589 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700590 // void map() {
591 // sphere(1.0);
592 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500593 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700594 // void main() {
595 // for (int i = 0; i < 1; i++) {
596 // map();
597 // }
598 // }
599 //
Greg Daniel64773e62016-11-22 09:44:03 -0500600 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
601 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700602 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
603 // the spec makes this make sense.
604// if (is_out(function->fParameters[i])) {
ethannicholasd598f792016-07-25 10:08:54 -0700605 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -0700606 SpvStorageClassFunction));
607// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700608// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700609// }
610 }
611 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
612 this->writeWord(result, fConstantBuffer);
613 this->writeWord(returnType, fConstantBuffer);
614 for (SpvId id : parameterTypes) {
615 this->writeWord(id, fConstantBuffer);
616 }
617 fTypeMap[key] = result;
618 return result;
619 }
620 return entry->second;
621}
622
ethannicholas8ac838d2016-11-22 08:39:36 -0800623SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
624 return this->getPointerType(type, fDefaultLayout, storageClass);
625}
626
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400627SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700628 SpvStorageClass_ storageClass) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400629 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400630 String key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700631 auto entry = fTypeMap.find(key);
632 if (entry == fTypeMap.end()) {
633 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500634 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700635 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700636 fTypeMap[key] = result;
637 return result;
638 }
639 return entry->second;
640}
641
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400642SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700643 switch (expr.fKind) {
644 case Expression::kBinary_Kind:
645 return this->writeBinaryExpression((BinaryExpression&) expr, out);
646 case Expression::kBoolLiteral_Kind:
647 return this->writeBoolLiteral((BoolLiteral&) expr);
648 case Expression::kConstructor_Kind:
649 return this->writeConstructor((Constructor&) expr, out);
650 case Expression::kIntLiteral_Kind:
651 return this->writeIntLiteral((IntLiteral&) expr);
652 case Expression::kFieldAccess_Kind:
653 return this->writeFieldAccess(((FieldAccess&) expr), out);
654 case Expression::kFloatLiteral_Kind:
655 return this->writeFloatLiteral(((FloatLiteral&) expr));
656 case Expression::kFunctionCall_Kind:
657 return this->writeFunctionCall((FunctionCall&) expr, out);
658 case Expression::kPrefix_Kind:
659 return this->writePrefixExpression((PrefixExpression&) expr, out);
660 case Expression::kPostfix_Kind:
661 return this->writePostfixExpression((PostfixExpression&) expr, out);
662 case Expression::kSwizzle_Kind:
663 return this->writeSwizzle((Swizzle&) expr, out);
664 case Expression::kVariableReference_Kind:
665 return this->writeVariableReference((VariableReference&) expr, out);
666 case Expression::kTernary_Kind:
667 return this->writeTernaryExpression((TernaryExpression&) expr, out);
668 case Expression::kIndex_Kind:
669 return this->writeIndexExpression((IndexExpression&) expr, out);
670 default:
671 ABORT("unsupported expression: %s", expr.description().c_str());
672 }
673 return -1;
674}
675
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400676SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700677 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400678 SkASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -0700679 int32_t intrinsicId;
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400680 if (c.fArguments.size() > 0) {
681 const Type& type = c.fArguments[0]->fType;
682 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
683 intrinsicId = std::get<1>(intrinsic->second);
684 } else if (is_signed(fContext, type)) {
685 intrinsicId = std::get<2>(intrinsic->second);
686 } else if (is_unsigned(fContext, type)) {
687 intrinsicId = std::get<3>(intrinsic->second);
688 } else if (is_bool(fContext, type)) {
689 intrinsicId = std::get<4>(intrinsic->second);
690 } else {
691 intrinsicId = std::get<1>(intrinsic->second);
692 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700693 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400694 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700695 }
696 switch (std::get<0>(intrinsic->second)) {
697 case kGLSL_STD_450_IntrinsicKind: {
698 SpvId result = this->nextId();
699 std::vector<SpvId> arguments;
700 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400701 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
702 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
703 } else {
704 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
705 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700706 }
707 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700708 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700709 this->writeWord(result, out);
710 this->writeWord(fGLSLExtendedInstructions, out);
711 this->writeWord(intrinsicId, out);
712 for (SpvId id : arguments) {
713 this->writeWord(id, out);
714 }
715 return result;
716 }
717 case kSPIRV_IntrinsicKind: {
718 SpvId result = this->nextId();
719 std::vector<SpvId> arguments;
720 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400721 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
722 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
723 } else {
724 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
725 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700726 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400727 if (c.fType != *fContext.fVoid_Type) {
728 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
729 this->writeWord(this->getType(c.fType), out);
730 this->writeWord(result, out);
731 } else {
732 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
733 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700734 for (SpvId id : arguments) {
735 this->writeWord(id, out);
736 }
737 return result;
738 }
739 case kSpecial_IntrinsicKind:
740 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
741 default:
742 ABORT("unsupported intrinsic kind");
743 }
744}
745
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500746std::vector<SpvId> SPIRVCodeGenerator::vectorize(
747 const std::vector<std::unique_ptr<Expression>>& args,
748 OutputStream& out) {
749 int vectorSize = 0;
750 for (const auto& a : args) {
751 if (a->fType.kind() == Type::kVector_Kind) {
752 if (vectorSize) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400753 SkASSERT(a->fType.columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500754 }
755 else {
756 vectorSize = a->fType.columns();
757 }
758 }
759 }
760 std::vector<SpvId> result;
761 for (const auto& a : args) {
762 SpvId raw = this->writeExpression(*a, out);
763 if (vectorSize && a->fType.kind() == Type::kScalar_Kind) {
764 SpvId vector = this->nextId();
765 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
766 this->writeWord(this->getType(a->fType.toCompound(fContext, vectorSize, 1)), out);
767 this->writeWord(vector, out);
768 for (int i = 0; i < vectorSize; i++) {
769 this->writeWord(raw, out);
770 }
Ethan Nicholas151a8832019-04-16 12:07:26 -0400771 this->writePrecisionModifier(a->fType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500772 result.push_back(vector);
773 } else {
774 result.push_back(raw);
775 }
776 }
777 return result;
778}
779
780void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
781 SpvId signedInst, SpvId unsignedInst,
782 const std::vector<SpvId>& args,
783 OutputStream& out) {
784 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
785 this->writeWord(this->getType(type), out);
786 this->writeWord(id, out);
787 this->writeWord(fGLSLExtendedInstructions, out);
788
789 if (is_float(fContext, type)) {
790 this->writeWord(floatInst, out);
791 } else if (is_signed(fContext, type)) {
792 this->writeWord(signedInst, out);
793 } else if (is_unsigned(fContext, type)) {
794 this->writeWord(unsignedInst, out);
795 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400796 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500797 }
798 for (SpvId a : args) {
799 this->writeWord(a, out);
800 }
801}
802
Greg Daniel64773e62016-11-22 09:44:03 -0500803SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400804 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700805 SpvId result = this->nextId();
806 switch (kind) {
807 case kAtan_SpecialIntrinsic: {
808 std::vector<SpvId> arguments;
809 for (size_t i = 0; i < c.fArguments.size(); i++) {
810 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
811 }
812 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700813 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700814 this->writeWord(result, out);
815 this->writeWord(fGLSLExtendedInstructions, out);
816 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
817 for (SpvId id : arguments) {
818 this->writeWord(id, out);
819 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400820 break;
821 }
822 case kSubpassLoad_SpecialIntrinsic: {
823 SpvId img = this->writeExpression(*c.fArguments[0], out);
824 std::vector<std::unique_ptr<Expression>> args;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700825 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
826 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
827 Constructor ctor(-1, *fContext.fFloat2_Type, std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400828 SpvId coords = this->writeConstantVector(ctor);
829 if (1 == c.fArguments.size()) {
830 this->writeInstruction(SpvOpImageRead,
831 this->getType(c.fType),
832 result,
833 img,
834 coords,
835 out);
836 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400837 SkASSERT(2 == c.fArguments.size());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400838 SpvId sample = this->writeExpression(*c.fArguments[1], out);
839 this->writeInstruction(SpvOpImageRead,
840 this->getType(c.fType),
841 result,
842 img,
843 coords,
844 SpvImageOperandsSampleMask,
845 sample,
846 out);
847 }
848 break;
849 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700850 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500851 SpvOp_ op = SpvOpImageSampleImplicitLod;
852 switch (c.fArguments[0]->fType.dimensions()) {
853 case SpvDim1D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400854 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500855 op = SpvOpImageSampleProjImplicitLod;
856 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400857 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500858 }
859 break;
860 case SpvDim2D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400861 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500862 op = SpvOpImageSampleProjImplicitLod;
863 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400864 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500865 }
866 break;
867 case SpvDim3D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400868 if (c.fArguments[1]->fType == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500869 op = SpvOpImageSampleProjImplicitLod;
870 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400871 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500872 }
873 break;
874 case SpvDimCube: // fall through
875 case SpvDimRect: // fall through
876 case SpvDimBuffer: // fall through
877 case SpvDimSubpassData:
878 break;
879 }
ethannicholasd598f792016-07-25 10:08:54 -0700880 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700881 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
882 SpvId uv = this->writeExpression(*c.fArguments[1], out);
883 if (c.fArguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500884 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700885 SpvImageOperandsBiasMask,
886 this->writeExpression(*c.fArguments[2], out),
887 out);
888 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400889 SkASSERT(c.fArguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500890 if (fProgram.fSettings.fSharpenTextures) {
891 FloatLiteral lodBias(fContext, -1, -0.5);
892 this->writeInstruction(op, type, result, sampler, uv,
893 SpvImageOperandsBiasMask,
894 this->writeFloatLiteral(lodBias),
895 out);
896 } else {
897 this->writeInstruction(op, type, result, sampler, uv,
898 out);
899 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700900 }
901 break;
902 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500903 case kMod_SpecialIntrinsic: {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500904 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400905 SkASSERT(args.size() == 2);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500906 const Type& operandType = c.fArguments[0]->fType;
907 SpvOp_ op;
908 if (is_float(fContext, operandType)) {
909 op = SpvOpFMod;
910 } else if (is_signed(fContext, operandType)) {
911 op = SpvOpSMod;
912 } else if (is_unsigned(fContext, operandType)) {
913 op = SpvOpUMod;
914 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400915 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500916 return 0;
917 }
918 this->writeOpCode(op, 5, out);
919 this->writeWord(this->getType(operandType), out);
920 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500921 this->writeWord(args[0], out);
922 this->writeWord(args[1], out);
923 break;
924 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700925 case kDFdy_SpecialIntrinsic: {
926 SpvId fn = this->writeExpression(*c.fArguments[0], out);
927 this->writeOpCode(SpvOpDPdy, 4, out);
928 this->writeWord(this->getType(c.fType), out);
929 this->writeWord(result, out);
930 this->writeWord(fn, out);
931 if (fProgram.fSettings.fFlipY) {
932 // Flipping Y also negates the Y derivatives.
933 SpvId flipped = this->nextId();
934 this->writeInstruction(SpvOpFNegate, this->getType(c.fType), flipped, result, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -0400935 this->writePrecisionModifier(c.fType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700936 return flipped;
937 }
938 break;
939 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500940 case kClamp_SpecialIntrinsic: {
941 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400942 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500943 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
944 GLSLstd450UClamp, args, out);
945 break;
946 }
947 case kMax_SpecialIntrinsic: {
948 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400949 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500950 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMax, GLSLstd450SMax,
951 GLSLstd450UMax, args, out);
952 break;
953 }
954 case kMin_SpecialIntrinsic: {
955 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400956 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500957 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMin, GLSLstd450SMin,
958 GLSLstd450UMin, args, out);
959 break;
960 }
961 case kMix_SpecialIntrinsic: {
962 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400963 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500964 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMix, SpvOpUndef,
965 SpvOpUndef, args, out);
966 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500967 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400968 case kSaturate_SpecialIntrinsic: {
969 SkASSERT(c.fArguments.size() == 1);
970 std::vector<std::unique_ptr<Expression>> finalArgs;
971 finalArgs.push_back(c.fArguments[0]->clone());
972 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 0));
973 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 1));
974 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
975 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
976 GLSLstd450UClamp, spvArgs, out);
977 break;
978 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700979 }
980 return result;
981}
982
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400983SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700984 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -0700985 if (entry == fFunctionMap.end()) {
986 return this->writeIntrinsicCall(c, out);
987 }
988 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -0400989 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
ethannicholasb3058bd2016-07-01 08:22:01 -0700990 std::vector<SpvId> arguments;
991 for (size_t i = 0; i < c.fArguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500992 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -0700993 // passed directly
994 SpvId tmpVar;
995 // if we need a temporary var to store this argument, this is the value to store in the var
996 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -0700997 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700998 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
999 SpvId ptr = lv->getPointer();
1000 if (ptr) {
1001 arguments.push_back(ptr);
1002 continue;
1003 } else {
1004 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1005 // copy it into a temp, call the function, read the value out of the temp, and then
1006 // update the lvalue.
1007 tmpValueId = lv->load(out);
1008 tmpVar = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001009 lvalues.push_back(std::make_tuple(tmpVar, &c.fArguments[i]->fType, std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001010 }
1011 } else {
1012 // see getFunctionType for an explanation of why we're always using pointer parameters
1013 tmpValueId = this->writeExpression(*c.fArguments[i], out);
1014 tmpVar = this->nextId();
1015 }
Greg Daniel64773e62016-11-22 09:44:03 -05001016 this->writeInstruction(SpvOpVariable,
1017 this->getPointerType(c.fArguments[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -07001018 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001019 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001020 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001021 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001022 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1023 arguments.push_back(tmpVar);
1024 }
1025 SpvId result = this->nextId();
1026 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001027 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001028 this->writeWord(result, out);
1029 this->writeWord(entry->second, out);
1030 for (SpvId id : arguments) {
1031 this->writeWord(id, out);
1032 }
1033 // now that the call is complete, we may need to update some lvalues with the new values of out
1034 // arguments
1035 for (const auto& tuple : lvalues) {
1036 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001037 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1038 out);
1039 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001040 std::get<2>(tuple)->store(load, out);
1041 }
1042 return result;
1043}
1044
ethannicholasf789b382016-08-03 12:43:36 -07001045SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001046 SkASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001047 SpvId result = this->nextId();
1048 std::vector<SpvId> arguments;
1049 for (size_t i = 0; i < c.fArguments.size(); i++) {
1050 arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1051 }
ethannicholasd598f792016-07-25 10:08:54 -07001052 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001053 if (c.fArguments.size() == 1) {
1054 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001055 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001056 this->writeWord(type, fConstantBuffer);
1057 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001058 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001059 this->writeWord(arguments[0], fConstantBuffer);
1060 }
1061 } else {
Greg Daniel64773e62016-11-22 09:44:03 -05001062 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001063 fConstantBuffer);
1064 this->writeWord(type, fConstantBuffer);
1065 this->writeWord(result, fConstantBuffer);
1066 for (SpvId id : arguments) {
1067 this->writeWord(id, fConstantBuffer);
1068 }
1069 }
1070 return result;
1071}
1072
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001073SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001074 SkASSERT(c.fType.isFloat());
1075 SkASSERT(c.fArguments.size() == 1);
1076 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001077 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.isSigned()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001080 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001081 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001082 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001083 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Greg Daniel64773e62016-11-22 09:44:03 -05001084 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001085 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001086 }
1087 return result;
1088}
1089
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001090SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001091 SkASSERT(c.fType.isSigned());
1092 SkASSERT(c.fArguments.size() == 1);
1093 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001094 SpvId result = this->nextId();
1095 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001096 if (c.fArguments[0]->fType.isFloat()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001097 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001098 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001099 }
1100 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001101 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001102 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001103 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001104 }
1105 return result;
1106}
1107
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001108SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001109 SkASSERT(c.fType.isUnsigned());
1110 SkASSERT(c.fArguments.size() == 1);
1111 SkASSERT(c.fArguments[0]->fType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001112 SpvId result = this->nextId();
1113 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001114 if (c.fArguments[0]->fType.isFloat()) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001115 this->writeInstruction(SpvOpConvertFToU, this->getType(c.fType), result, parameter,
1116 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001117 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001118 SkASSERT(c.fArguments[0]->fType.isSigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001119 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
1120 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001121 }
1122 return result;
1123}
1124
Ethan Nicholas84645e32017-02-09 13:57:14 -05001125void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001126 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001127 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001128 SpvId zeroId = this->writeFloatLiteral(zero);
1129 std::vector<SpvId> columnIds;
1130 for (int column = 0; column < type.columns(); column++) {
1131 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1132 out);
1133 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1134 out);
1135 SpvId columnId = this->nextId();
1136 this->writeWord(columnId, out);
1137 columnIds.push_back(columnId);
1138 for (int row = 0; row < type.columns(); row++) {
1139 this->writeWord(row == column ? diagonal : zeroId, out);
1140 }
Ethan Nicholas151a8832019-04-16 12:07:26 -04001141 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001142 }
1143 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1144 out);
1145 this->writeWord(this->getType(type), out);
1146 this->writeWord(id, out);
1147 for (SpvId id : columnIds) {
1148 this->writeWord(id, out);
1149 }
Ethan Nicholas151a8832019-04-16 12:07:26 -04001150 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001151}
1152
1153void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001154 const Type& dstType, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001155 SkASSERT(srcType.kind() == Type::kMatrix_Kind);
1156 SkASSERT(dstType.kind() == Type::kMatrix_Kind);
1157 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001158 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1159 srcType.rows(),
1160 1));
1161 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1162 dstType.rows(),
1163 1));
1164 SpvId zeroId;
1165 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001166 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001167 zeroId = this->writeFloatLiteral(zero);
1168 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001169 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001170 zeroId = this->writeIntLiteral(zero);
1171 } else {
1172 ABORT("unsupported matrix component type");
1173 }
1174 SpvId zeroColumn = 0;
1175 SpvId columns[4];
1176 for (int i = 0; i < dstType.columns(); i++) {
1177 if (i < srcType.columns()) {
1178 // we're still inside the src matrix, copy the column
1179 SpvId srcColumn = this->nextId();
1180 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholas151a8832019-04-16 12:07:26 -04001181 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001182 SpvId dstColumn;
1183 if (srcType.rows() == dstType.rows()) {
1184 // columns are equal size, don't need to do anything
1185 dstColumn = srcColumn;
1186 }
1187 else if (dstType.rows() > srcType.rows()) {
1188 // dst column is bigger, need to zero-pad it
1189 dstColumn = this->nextId();
1190 int delta = dstType.rows() - srcType.rows();
1191 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1192 this->writeWord(dstColumnType, out);
1193 this->writeWord(dstColumn, out);
1194 this->writeWord(srcColumn, out);
1195 for (int i = 0; i < delta; ++i) {
1196 this->writeWord(zeroId, out);
1197 }
Ethan Nicholas151a8832019-04-16 12:07:26 -04001198 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001199 }
1200 else {
1201 // dst column is smaller, need to swizzle the src column
1202 dstColumn = this->nextId();
1203 int count = dstType.rows();
1204 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1205 this->writeWord(dstColumnType, out);
1206 this->writeWord(dstColumn, out);
1207 this->writeWord(srcColumn, out);
1208 this->writeWord(srcColumn, out);
1209 for (int i = 0; i < count; i++) {
1210 this->writeWord(i, out);
1211 }
Ethan Nicholas151a8832019-04-16 12:07:26 -04001212 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001213 }
1214 columns[i] = dstColumn;
1215 } else {
1216 // we're past the end of the src matrix, need a vector of zeroes
1217 if (!zeroColumn) {
1218 zeroColumn = this->nextId();
1219 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1220 this->writeWord(dstColumnType, out);
1221 this->writeWord(zeroColumn, out);
1222 for (int i = 0; i < dstType.rows(); ++i) {
1223 this->writeWord(zeroId, out);
1224 }
Ethan Nicholas151a8832019-04-16 12:07:26 -04001225 this->writePrecisionModifier(dstType, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001226 }
1227 columns[i] = zeroColumn;
1228 }
1229 }
1230 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1231 this->writeWord(this->getType(dstType), out);
1232 this->writeWord(id, out);
1233 for (int i = 0; i < dstType.columns(); i++) {
1234 this->writeWord(columns[i], out);
1235 }
Ethan Nicholas151a8832019-04-16 12:07:26 -04001236 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001237}
1238
Ethan Nicholas151a8832019-04-16 12:07:26 -04001239void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1240 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001241 std::vector<SpvId>* columnIds,
1242 int* currentCount, int rows, SpvId entry,
1243 OutputStream& out) {
1244 SkASSERT(*currentCount < rows);
1245 ++(*currentCount);
1246 currentColumn->push_back(entry);
1247 if (*currentCount == rows) {
1248 *currentCount = 0;
1249 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1250 this->writeWord(columnType, out);
1251 SpvId columnId = this->nextId();
1252 this->writeWord(columnId, out);
1253 columnIds->push_back(columnId);
1254 for (SpvId id : *currentColumn) {
1255 this->writeWord(id, out);
1256 }
1257 currentColumn->clear();
Ethan Nicholas151a8832019-04-16 12:07:26 -04001258 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001259 }
1260}
1261
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001262SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001263 SkASSERT(c.fType.kind() == Type::kMatrix_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001264 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1265 // an instruction
1266 std::vector<SpvId> arguments;
1267 for (size_t i = 0; i < c.fArguments.size(); i++) {
1268 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1269 }
1270 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001271 int rows = c.fType.rows();
1272 int columns = c.fType.columns();
Ethan Nicholas84645e32017-02-09 13:57:14 -05001273 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1274 this->writeUniformScaleMatrix(result, arguments[0], c.fType, out);
1275 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kMatrix_Kind) {
1276 this->writeMatrixCopy(result, arguments[0], c.fArguments[0]->fType, c.fType, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001277 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kVector_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001278 SkASSERT(c.fType.rows() == 2 && c.fType.columns() == 2);
1279 SkASSERT(c.fArguments[0]->fType.columns() == 4);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001280 SpvId componentType = this->getType(c.fType.componentType());
1281 SpvId v[4];
1282 for (int i = 0; i < 4; ++i) {
1283 v[i] = this->nextId();
1284 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i, out);
1285 }
1286 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, 2, 1));
1287 SpvId column1 = this->nextId();
1288 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1289 SpvId column2 = this->nextId();
1290 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
1291 this->writeInstruction(SpvOpCompositeConstruct, this->getType(c.fType), result, column1,
1292 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001293 } else {
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001294 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001295 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001296 // ids of vectors and scalars we have written to the current column so far
1297 std::vector<SpvId> currentColumn;
1298 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001299 int currentCount = 0;
Ethan Nicholas151a8832019-04-16 12:07:26 -04001300 Precision precision = c.fType.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001301 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001302 if (currentCount == 0 && c.fArguments[i]->fType.kind() == Type::kVector_Kind &&
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001303 c.fArguments[i]->fType.columns() == c.fType.rows()) {
1304 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001305 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001306 } else {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001307 if (c.fArguments[i]->fType.columns() == 1) {
Ethan Nicholas151a8832019-04-16 12:07:26 -04001308 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1309 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001310 } else {
1311 SpvId componentType = this->getType(c.fArguments[i]->fType.componentType());
Ethan Nicholas811b9442018-05-11 13:16:03 -04001312 for (int j = 0; j < c.fArguments[i]->fType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001313 SpvId swizzle = this->nextId();
1314 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1315 arguments[i], j, out);
Ethan Nicholas151a8832019-04-16 12:07:26 -04001316 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1317 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001318 }
1319 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001320 }
1321 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001322 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001323 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001324 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001325 this->writeWord(result, out);
1326 for (SpvId id : columnIds) {
1327 this->writeWord(id, out);
1328 }
1329 }
Ethan Nicholas151a8832019-04-16 12:07:26 -04001330 this->writePrecisionModifier(c.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001331 return result;
1332}
1333
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001334SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001335 SkASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001336 if (c.isConstant()) {
1337 return this->writeConstantVector(c);
1338 }
1339 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1340 // an instruction
1341 std::vector<SpvId> arguments;
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001342 for (size_t i = 0; i < c.fArguments.size(); i++) {
1343 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
1344 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1345 // extract the components and convert them in that case manually. On top of that,
1346 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1347 // doesn't handle vector arguments at all, so we always extract vector components and
1348 // pass them into OpCreateComposite individually.
1349 SpvId vec = this->writeExpression(*c.fArguments[i], out);
1350 SpvOp_ op = SpvOpUndef;
1351 const Type& src = c.fArguments[i]->fType.componentType();
1352 const Type& dst = c.fType.componentType();
1353 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1354 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1355 if (c.fArguments.size() == 1) {
1356 return vec;
1357 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001358 } else if (src == *fContext.fInt_Type ||
1359 src == *fContext.fShort_Type ||
1360 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001361 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001362 } else if (src == *fContext.fUInt_Type ||
1363 src == *fContext.fUShort_Type ||
1364 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001365 op = SpvOpConvertUToF;
1366 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001367 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001368 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001369 } else if (dst == *fContext.fInt_Type ||
1370 dst == *fContext.fShort_Type ||
1371 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001372 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1373 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001374 } else if (src == *fContext.fInt_Type ||
1375 src == *fContext.fShort_Type ||
1376 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001377 if (c.fArguments.size() == 1) {
1378 return vec;
1379 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001380 } else if (src == *fContext.fUInt_Type ||
1381 src == *fContext.fUShort_Type ||
1382 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001383 op = SpvOpBitcast;
1384 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001385 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001386 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001387 } else if (dst == *fContext.fUInt_Type ||
1388 dst == *fContext.fUShort_Type ||
1389 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001390 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1391 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001392 } else if (src == *fContext.fInt_Type ||
1393 src == *fContext.fShort_Type ||
1394 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001395 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001396 } else if (src == *fContext.fUInt_Type ||
1397 src == *fContext.fUShort_Type ||
1398 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001399 if (c.fArguments.size() == 1) {
1400 return vec;
1401 }
1402 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001403 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001404 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001405 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001406 for (int j = 0; j < c.fArguments[i]->fType.columns(); j++) {
1407 SpvId swizzle = this->nextId();
1408 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1409 out);
1410 if (op != SpvOpUndef) {
1411 SpvId cast = this->nextId();
1412 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1413 arguments.push_back(cast);
1414 } else {
1415 arguments.push_back(swizzle);
1416 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001417 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001418 } else {
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001419 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1420 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001421 }
1422 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001423 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1424 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1425 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001426 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001427 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001428 this->writeWord(arguments[0], out);
1429 }
1430 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001431 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001432 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001433 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001434 this->writeWord(result, out);
1435 for (SpvId id : arguments) {
1436 this->writeWord(id, out);
1437 }
1438 }
1439 return result;
1440}
1441
Ethan Nicholasbd553222017-07-18 15:54:59 -04001442SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001443 SkASSERT(c.fType.kind() == Type::kArray_Kind);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001444 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1445 // an instruction
1446 std::vector<SpvId> arguments;
1447 for (size_t i = 0; i < c.fArguments.size(); i++) {
1448 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1449 }
1450 SpvId result = this->nextId();
1451 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
1452 this->writeWord(this->getType(c.fType), out);
1453 this->writeWord(result, out);
1454 for (SpvId id : arguments) {
1455 this->writeWord(id, out);
1456 }
1457 return result;
1458}
1459
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001460SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001461 if (c.fArguments.size() == 1 &&
1462 this->getActualType(c.fType) == this->getActualType(c.fArguments[0]->fType)) {
1463 return this->writeExpression(*c.fArguments[0], out);
1464 }
1465 if (c.fType == *fContext.fFloat_Type || c.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001466 return this->writeFloatConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001467 } else if (c.fType == *fContext.fInt_Type ||
1468 c.fType == *fContext.fShort_Type ||
1469 c.fType == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001470 return this->writeIntConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001471 } else if (c.fType == *fContext.fUInt_Type ||
1472 c.fType == *fContext.fUShort_Type ||
1473 c.fType == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001474 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001475 }
ethannicholasd598f792016-07-25 10:08:54 -07001476 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001477 case Type::kVector_Kind:
1478 return this->writeVectorConstructor(c, out);
1479 case Type::kMatrix_Kind:
1480 return this->writeMatrixConstructor(c, out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001481 case Type::kArray_Kind:
1482 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001483 default:
1484 ABORT("unsupported constructor: %s", c.description().c_str());
1485 }
1486}
1487
1488SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1489 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001490 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001491 return SpvStorageClassInput;
1492 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001493 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001494 return SpvStorageClassOutput;
1495 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001496 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001497 return SpvStorageClassPushConstant;
1498 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001499 return SpvStorageClassUniform;
1500 } else {
1501 return SpvStorageClassFunction;
1502 }
1503}
1504
ethannicholasf789b382016-08-03 12:43:36 -07001505SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001506 switch (expr.fKind) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001507 case Expression::kVariableReference_Kind: {
1508 const Variable& var = ((VariableReference&) expr).fVariable;
1509 if (var.fStorage != Variable::kGlobal_Storage) {
1510 return SpvStorageClassFunction;
1511 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001512 SpvStorageClass_ result = get_storage_class(var.fModifiers);
1513 if (result == SpvStorageClassFunction) {
1514 result = SpvStorageClassPrivate;
1515 }
1516 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001517 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001518 case Expression::kFieldAccess_Kind:
1519 return get_storage_class(*((FieldAccess&) expr).fBase);
1520 case Expression::kIndex_Kind:
1521 return get_storage_class(*((IndexExpression&) expr).fBase);
1522 default:
1523 return SpvStorageClassFunction;
1524 }
1525}
1526
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001527std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001528 std::vector<SpvId> chain;
1529 switch (expr.fKind) {
1530 case Expression::kIndex_Kind: {
1531 IndexExpression& indexExpr = (IndexExpression&) expr;
1532 chain = this->getAccessChain(*indexExpr.fBase, out);
1533 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1534 break;
1535 }
1536 case Expression::kFieldAccess_Kind: {
1537 FieldAccess& fieldExpr = (FieldAccess&) expr;
1538 chain = this->getAccessChain(*fieldExpr.fBase, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001539 IntLiteral index(fContext, -1, fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001540 chain.push_back(this->writeIntLiteral(index));
1541 break;
1542 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001543 default: {
1544 SpvId id = this->getLValue(expr, out)->getPointer();
1545 SkASSERT(id != 0);
1546 chain.push_back(id);
1547 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001548 }
1549 return chain;
1550}
1551
1552class PointerLValue : public SPIRVCodeGenerator::LValue {
1553public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001554 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1555 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001556 : fGen(gen)
1557 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001558 , fType(type)
1559 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001560
1561 virtual SpvId getPointer() override {
1562 return fPointer;
1563 }
1564
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001565 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001566 SpvId result = fGen.nextId();
1567 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001568 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001569 return result;
1570 }
1571
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001572 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001573 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1574 }
1575
1576private:
1577 SPIRVCodeGenerator& fGen;
1578 const SpvId fPointer;
1579 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001580 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001581};
1582
1583class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1584public:
Greg Daniel64773e62016-11-22 09:44:03 -05001585 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001586 const Type& baseType, const Type& swizzleType,
1587 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001588 : fGen(gen)
1589 , fVecPointer(vecPointer)
1590 , fComponents(components)
1591 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001592 , fSwizzleType(swizzleType)
1593 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001594
1595 virtual SpvId getPointer() override {
1596 return 0;
1597 }
1598
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001599 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001600 SpvId base = fGen.nextId();
1601 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001602 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001603 SpvId result = fGen.nextId();
1604 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1605 fGen.writeWord(fGen.getType(fSwizzleType), out);
1606 fGen.writeWord(result, out);
1607 fGen.writeWord(base, out);
1608 fGen.writeWord(base, out);
1609 for (int component : fComponents) {
1610 fGen.writeWord(component, out);
1611 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001612 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001613 return result;
1614 }
1615
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001616 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001617 // use OpVectorShuffle to mix and match the vector components. We effectively create
1618 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001619 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001620 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001621 // float3L = ...;
1622 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001623 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001624 // 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 -07001625 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1626 // (3, 1, 4).
1627 SpvId base = fGen.nextId();
1628 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1629 SpvId shuffle = fGen.nextId();
1630 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1631 fGen.writeWord(fGen.getType(fBaseType), out);
1632 fGen.writeWord(shuffle, out);
1633 fGen.writeWord(base, out);
1634 fGen.writeWord(value, out);
1635 for (int i = 0; i < fBaseType.columns(); i++) {
1636 // current offset into the virtual vector, defaults to pulling the unmodified
1637 // value from the left side
1638 int offset = i;
1639 // check to see if we are writing this component
1640 for (size_t j = 0; j < fComponents.size(); j++) {
1641 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001642 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001643 // the correct component of the right side instead of preserving the
1644 // value from the left
1645 offset = (int) (j + fBaseType.columns());
1646 break;
1647 }
1648 }
1649 fGen.writeWord(offset, out);
1650 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001651 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001652 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1653 }
1654
1655private:
1656 SPIRVCodeGenerator& fGen;
1657 const SpvId fVecPointer;
1658 const std::vector<int>& fComponents;
1659 const Type& fBaseType;
1660 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001661 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001662};
1663
Greg Daniel64773e62016-11-22 09:44:03 -05001664std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001665 OutputStream& out) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001666 Precision precision = expr.fType.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001667 switch (expr.fKind) {
1668 case Expression::kVariableReference_Kind: {
Ethan Nicholas5226b772018-05-03 16:20:41 -04001669 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07001670 const Variable& var = ((VariableReference&) expr).fVariable;
Ethan Nicholas5226b772018-05-03 16:20:41 -04001671 if (var.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
1672 type = this->getType(Type("sk_in", Type::kArray_Kind, var.fType.componentType(),
1673 fSkInCount));
1674 } else {
1675 type = this->getType(expr.fType);
1676 }
ethannicholasd598f792016-07-25 10:08:54 -07001677 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001678 SkASSERT(entry != fVariableMap.end());
Ethan Nicholas5226b772018-05-03 16:20:41 -04001679 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(*this,
1680 entry->second,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001681 type,
1682 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001683 }
1684 case Expression::kIndex_Kind: // fall through
1685 case Expression::kFieldAccess_Kind: {
1686 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1687 SpvId member = this->nextId();
1688 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001689 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001690 this->writeWord(member, out);
1691 for (SpvId idx : chain) {
1692 this->writeWord(idx, out);
1693 }
1694 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -04001695 *this,
1696 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001697 this->getType(expr.fType),
1698 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001699 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001700 case Expression::kSwizzle_Kind: {
1701 Swizzle& swizzle = (Swizzle&) expr;
1702 size_t count = swizzle.fComponents.size();
1703 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001704 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001705 if (count == 1) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001706 IntLiteral index(fContext, -1, swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001707 SpvId member = this->nextId();
1708 this->writeInstruction(SpvOpAccessChain,
Greg Daniel64773e62016-11-22 09:44:03 -05001709 this->getPointerType(swizzle.fType,
1710 get_storage_class(*swizzle.fBase)),
1711 member,
1712 base,
1713 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001714 out);
1715 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1716 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001717 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001718 this->getType(expr.fType),
1719 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001720 } else {
1721 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
Greg Daniel64773e62016-11-22 09:44:03 -05001722 *this,
1723 base,
1724 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001725 swizzle.fBase->fType,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001726 expr.fType,
1727 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001728 }
1729 }
Ethan Nicholasa583b812018-01-18 13:32:11 -05001730 case Expression::kTernary_Kind: {
1731 TernaryExpression& t = (TernaryExpression&) expr;
1732 SpvId test = this->writeExpression(*t.fTest, out);
1733 SpvId end = this->nextId();
1734 SpvId ifTrueLabel = this->nextId();
1735 SpvId ifFalseLabel = this->nextId();
1736 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1737 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1738 this->writeLabel(ifTrueLabel, out);
1739 SpvId ifTrue = this->getLValue(*t.fIfTrue, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001740 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001741 this->writeInstruction(SpvOpBranch, end, out);
1742 ifTrueLabel = fCurrentBlock;
1743 SpvId ifFalse = this->getLValue(*t.fIfFalse, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001744 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001745 ifFalseLabel = fCurrentBlock;
1746 this->writeInstruction(SpvOpBranch, end, out);
1747 SpvId result = this->nextId();
1748 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1749 ifTrueLabel, ifFalse, ifFalseLabel, out);
1750 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1751 *this,
1752 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001753 this->getType(expr.fType),
1754 precision));
Ethan Nicholasa583b812018-01-18 13:32:11 -05001755 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001756 default:
1757 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001758 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001759 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1760 // caught by IRGenerator
1761 SpvId result = this->nextId();
1762 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001763 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1764 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001765 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1766 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1767 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001768 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001769 this->getType(expr.fType),
1770 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001771 }
1772}
1773
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001774SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001775 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001776 auto entry = fVariableMap.find(&ref.fVariable);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001777 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001778 SpvId var = entry->second;
ethannicholasd598f792016-07-25 10:08:54 -07001779 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001780 this->writePrecisionModifier(ref.fVariable.fType, result);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001781 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
1782 fProgram.fSettings.fFlipY) {
1783 // need to remap to a top-left coordinate system
Greg Daniele6ab9982018-08-22 13:56:32 +00001784 if (fRTHeightStructId == (SpvId) -1) {
1785 // height variable hasn't been written yet
1786 std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors));
1787 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
1788 std::vector<Type::Field> fields;
1789 fields.emplace_back(Modifiers(), SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1790 StringFragment name("sksl_synthetic_uniforms");
1791 Type intfStruct(-1, name, fields);
1792 Layout layout(0, -1, -1, 1, -1, -1, -1, -1, Layout::Format::kUnspecified,
1793 Layout::kUnspecified_Primitive, -1, -1, "", Layout::kNo_Key,
Ethan Nicholas78aceb22018-08-31 16:13:58 -04001794 Layout::CType::kDefault);
Greg Daniele6ab9982018-08-22 13:56:32 +00001795 Variable* intfVar = new Variable(-1,
1796 Modifiers(layout, Modifiers::kUniform_Flag),
1797 name,
1798 intfStruct,
1799 Variable::kGlobal_Storage);
1800 fSynthetics.takeOwnership(intfVar);
1801 InterfaceBlock intf(-1, intfVar, name, String(""),
1802 std::vector<std::unique_ptr<Expression>>(), st);
1803 fRTHeightStructId = this->writeInterfaceBlock(intf);
1804 fRTHeightFieldIndex = 0;
1805 }
1806 SkASSERT(fRTHeightFieldIndex != (SpvId) -1);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001807 // write float4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, gl_FragCoord.w)
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001808 SpvId xId = this->nextId();
1809 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1810 result, 0, out);
Greg Daniele6ab9982018-08-22 13:56:32 +00001811 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1812 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1813 SpvId heightPtr = this->nextId();
1814 this->writeOpCode(SpvOpAccessChain, 5, out);
1815 this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out);
1816 this->writeWord(heightPtr, out);
1817 this->writeWord(fRTHeightStructId, out);
1818 this->writeWord(fieldIndexId, out);
1819 SpvId heightRead = this->nextId();
1820 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1821 heightPtr, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001822 SpvId rawYId = this->nextId();
1823 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1824 result, 1, out);
1825 SpvId flippedYId = this->nextId();
1826 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
Greg Daniele6ab9982018-08-22 13:56:32 +00001827 heightRead, rawYId, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001828 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001829 SpvId zeroId = writeFloatLiteral(zero);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001830 FloatLiteral one(fContext, -1, 1.0);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001831 SpvId wId = this->nextId();
1832 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), wId,
1833 result, 3, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001834 SpvId flipped = this->nextId();
1835 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001836 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001837 this->writeWord(flipped, out);
1838 this->writeWord(xId, out);
1839 this->writeWord(flippedYId, out);
1840 this->writeWord(zeroId, out);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001841 this->writeWord(wId, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001842 return flipped;
1843 }
Chris Daltonb91c4662018-08-01 10:46:22 -06001844 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
1845 !fProgram.fSettings.fFlipY) {
1846 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1847 // the default convention of "counter-clockwise face is front".
1848 SpvId inverse = this->nextId();
1849 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1850 result, out);
1851 return inverse;
1852 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001853 return result;
1854}
1855
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001856SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001857 if (expr.fBase->fType.kind() == Type::Kind::kVector_Kind) {
1858 SpvId base = this->writeExpression(*expr.fBase, out);
1859 SpvId index = this->writeExpression(*expr.fIndex, out);
1860 SpvId result = this->nextId();
1861 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.fType), result, base,
1862 index, out);
1863 return result;
1864 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001865 return getLValue(expr, out)->load(out);
1866}
1867
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001868SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001869 return getLValue(f, out)->load(out);
1870}
1871
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001872SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001873 SpvId base = this->writeExpression(*swizzle.fBase, out);
1874 SpvId result = this->nextId();
1875 size_t count = swizzle.fComponents.size();
1876 if (count == 1) {
Greg Daniel64773e62016-11-22 09:44:03 -05001877 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
1878 swizzle.fComponents[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001879 } else {
1880 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
ethannicholasd598f792016-07-25 10:08:54 -07001881 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001882 this->writeWord(result, out);
1883 this->writeWord(base, out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001884 SpvId other;
1885 int last = swizzle.fComponents.back();
1886 if (last < 0) {
1887 if (!fConstantZeroOneVector) {
1888 FloatLiteral zero(fContext, -1, 0);
1889 SpvId zeroId = this->writeFloatLiteral(zero);
1890 FloatLiteral one(fContext, -1, 1);
Ethan Nicholas0b2c0542019-02-25 14:29:11 -05001891 SpvId oneId = this->writeFloatLiteral(one);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001892 SpvId type = this->getType(*fContext.fFloat2_Type);
1893 fConstantZeroOneVector = this->nextId();
1894 this->writeOpCode(SpvOpConstantComposite, 5, fConstantBuffer);
1895 this->writeWord(type, fConstantBuffer);
1896 this->writeWord(fConstantZeroOneVector, fConstantBuffer);
1897 this->writeWord(zeroId, fConstantBuffer);
1898 this->writeWord(oneId, fConstantBuffer);
1899 }
1900 other = fConstantZeroOneVector;
1901 } else {
1902 other = base;
1903 }
1904 this->writeWord(other, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001905 for (int component : swizzle.fComponents) {
Ethan Nicholasac285b12019-02-12 16:05:18 -05001906 if (component == SKSL_SWIZZLE_0) {
Ethan Nicholas0b2c0542019-02-25 14:29:11 -05001907 this->writeWord(swizzle.fBase->fType.columns(), out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001908 } else if (component == SKSL_SWIZZLE_1) {
Ethan Nicholas0b2c0542019-02-25 14:29:11 -05001909 this->writeWord(swizzle.fBase->fType.columns() + 1, out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001910 } else {
1911 this->writeWord(component, out);
1912 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001913 }
1914 }
1915 return result;
1916}
1917
Greg Daniel64773e62016-11-22 09:44:03 -05001918SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1919 const Type& operandType, SpvId lhs,
1920 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001921 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001922 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001923 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001924 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001925 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001926 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001927 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001928 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001929 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001930 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001931 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07001932 } else {
1933 ABORT("invalid operandType: %s", operandType.description().c_str());
1934 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04001935 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001936 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
1937 fDecorationBuffer);
1938 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001939 return result;
1940}
1941
Ethan Nicholas48e24052018-03-14 13:51:39 -04001942SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
1943 OutputStream& out) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05001944 if (operandType.kind() == Type::kVector_Kind) {
1945 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001946 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05001947 return result;
1948 }
1949 return id;
1950}
1951
Ethan Nicholas68990be2017-07-13 09:36:52 -04001952SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
1953 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04001954 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04001955 OutputStream& out) {
1956 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001957 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0df21132018-07-10 09:37:51 -04001958 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
1959 operandType.rows(),
1960 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04001961 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04001962 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04001963 1));
1964 SpvId boolType = this->getType(*fContext.fBool_Type);
1965 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04001966 for (int i = 0; i < operandType.columns(); i++) {
1967 SpvId columnL = this->nextId();
1968 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
1969 SpvId columnR = this->nextId();
1970 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04001971 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04001972 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
1973 SpvId merge = this->nextId();
1974 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04001975 if (result != 0) {
1976 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04001977 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04001978 result = next;
1979 }
1980 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04001981 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04001982 }
1983 }
1984 return result;
1985}
1986
Ethan Nicholas0df21132018-07-10 09:37:51 -04001987SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
1988 SpvId rhs, SpvOp_ floatOperator,
1989 SpvOp_ intOperator,
1990 OutputStream& out) {
1991 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
1992 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
1993 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
1994 operandType.rows(),
1995 1));
1996 SpvId columns[4];
1997 for (int i = 0; i < operandType.columns(); i++) {
1998 SpvId columnL = this->nextId();
1999 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2000 SpvId columnR = this->nextId();
2001 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2002 columns[i] = this->nextId();
2003 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2004 }
2005 SpvId result = this->nextId();
2006 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2007 this->writeWord(this->getType(operandType), out);
2008 this->writeWord(result, out);
2009 for (int i = 0; i < operandType.columns(); i++) {
2010 this->writeWord(columns[i], out);
2011 }
2012 return result;
2013}
2014
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002015SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002016 // handle cases where we don't necessarily evaluate both LHS and RHS
2017 switch (b.fOperator) {
2018 case Token::EQ: {
2019 SpvId rhs = this->writeExpression(*b.fRight, out);
2020 this->getLValue(*b.fLeft, out)->store(rhs, out);
2021 return rhs;
2022 }
2023 case Token::LOGICALAND:
2024 return this->writeLogicalAnd(b, out);
2025 case Token::LOGICALOR:
2026 return this->writeLogicalOr(b, out);
2027 default:
2028 break;
2029 }
2030
2031 // "normal" operators
ethannicholasd598f792016-07-25 10:08:54 -07002032 const Type& resultType = b.fType;
ethannicholasb3058bd2016-07-01 08:22:01 -07002033 std::unique_ptr<LValue> lvalue;
2034 SpvId lhs;
2035 if (is_assignment(b.fOperator)) {
2036 lvalue = this->getLValue(*b.fLeft, out);
2037 lhs = lvalue->load(out);
2038 } else {
2039 lvalue = nullptr;
2040 lhs = this->writeExpression(*b.fLeft, out);
2041 }
2042 SpvId rhs = this->writeExpression(*b.fRight, out);
Ethan Nicholas6feb6912017-06-30 12:23:36 -04002043 if (b.fOperator == Token::COMMA) {
2044 return rhs;
2045 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002046 Type tmp("<invalid>");
Ethan Nicholas48e24052018-03-14 13:51:39 -04002047 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002048 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002049 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2050 // handling in SPIR-V
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002051 if (this->getActualType(b.fLeft->fType) != this->getActualType(b.fRight->fType)) {
Greg Daniel64773e62016-11-22 09:44:03 -05002052 if (b.fLeft->fType.kind() == Type::kVector_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002053 b.fRight->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002054 // promote number to vector
2055 SpvId vec = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04002056 const Type& vecType = b.fLeft->fType;
2057 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2058 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002059 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002060 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002061 this->writeWord(rhs, out);
2062 }
2063 rhs = vec;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002064 operandType = &b.fLeft->fType;
Greg Daniel64773e62016-11-22 09:44:03 -05002065 } else if (b.fRight->fType.kind() == Type::kVector_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002066 b.fLeft->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002067 // promote number to vector
2068 SpvId vec = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04002069 const Type& vecType = b.fRight->fType;
2070 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2071 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002072 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002073 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002074 this->writeWord(lhs, out);
2075 }
2076 lhs = vec;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002077 SkASSERT(!lvalue);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002078 operandType = &b.fRight->fType;
ethannicholasd598f792016-07-25 10:08:54 -07002079 } else if (b.fLeft->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002080 SpvOp_ op;
ethannicholasd598f792016-07-25 10:08:54 -07002081 if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002082 op = SpvOpMatrixTimesMatrix;
ethannicholasd598f792016-07-25 10:08:54 -07002083 } else if (b.fRight->fType.kind() == Type::kVector_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002084 op = SpvOpMatrixTimesVector;
2085 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002086 SkASSERT(b.fRight->fType.kind() == Type::kScalar_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07002087 op = SpvOpMatrixTimesScalar;
2088 }
2089 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002090 this->writeInstruction(op, this->getType(b.fType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002091 if (b.fOperator == Token::STAREQ) {
2092 lvalue->store(result, out);
2093 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002094 SkASSERT(b.fOperator == Token::STAR);
ethannicholasb3058bd2016-07-01 08:22:01 -07002095 }
2096 return result;
ethannicholasd598f792016-07-25 10:08:54 -07002097 } else if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002098 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002099 if (b.fLeft->fType.kind() == Type::kVector_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05002100 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(b.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002101 lhs, rhs, out);
2102 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002103 SkASSERT(b.fLeft->fType.kind() == Type::kScalar_Kind);
Greg Daniel64773e62016-11-22 09:44:03 -05002104 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(b.fType), result, rhs,
ethannicholasb3058bd2016-07-01 08:22:01 -07002105 lhs, out);
2106 }
2107 if (b.fOperator == Token::STAREQ) {
2108 lvalue->store(result, out);
2109 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002110 SkASSERT(b.fOperator == Token::STAR);
ethannicholasb3058bd2016-07-01 08:22:01 -07002111 }
2112 return result;
2113 } else {
Ethan Nicholase1f55022019-02-05 17:17:40 -05002114 ABORT("unsupported binary expression: %s (%s, %s)", b.description().c_str(),
2115 b.fLeft->fType.description().c_str(), b.fRight->fType.description().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002116 }
2117 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002118 tmp = this->getActualType(b.fLeft->fType);
2119 operandType = &tmp;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002120 SkASSERT(*operandType == this->getActualType(b.fRight->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002121 }
2122 switch (b.fOperator) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002123 case Token::EQEQ: {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002124 if (operandType->kind() == Type::kMatrix_Kind) {
2125 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002126 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002127 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002128 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002129 const Type* tmpType;
2130 if (operandType->kind() == Type::kVector_Kind) {
2131 tmpType = &fContext.fBool_Type->toCompound(fContext,
2132 operandType->columns(),
2133 operandType->rows());
2134 } else {
2135 tmpType = &resultType;
2136 }
2137 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002138 SpvOpFOrdEqual, SpvOpIEqual,
2139 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002140 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002141 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002142 case Token::NEQ:
Ethan Nicholas68990be2017-07-13 09:36:52 -04002143 if (operandType->kind() == Type::kMatrix_Kind) {
2144 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002145 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002146 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002147 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002148 const Type* tmpType;
2149 if (operandType->kind() == Type::kVector_Kind) {
2150 tmpType = &fContext.fBool_Type->toCompound(fContext,
2151 operandType->columns(),
2152 operandType->rows());
2153 } else {
2154 tmpType = &resultType;
2155 }
2156 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002157 SpvOpFOrdNotEqual, SpvOpINotEqual,
2158 SpvOpINotEqual, SpvOpLogicalNotEqual,
2159 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002160 *operandType, SpvOpAny, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002161 case Token::GT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002162 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002163 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2164 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002165 SpvOpUGreaterThan, SpvOpUndef, out);
2166 case Token::LT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002167 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002168 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002169 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
2170 case Token::GTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002171 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002172 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2173 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002174 SpvOpUGreaterThanEqual, SpvOpUndef, out);
2175 case Token::LTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002176 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002177 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2178 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002179 SpvOpULessThanEqual, SpvOpUndef, out);
2180 case Token::PLUS:
Ethan Nicholas0df21132018-07-10 09:37:51 -04002181 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2182 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2183 SkASSERT(b.fLeft->fType == b.fRight->fType);
2184 return this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2185 SpvOpFAdd, SpvOpIAdd, out);
2186 }
Greg Daniel64773e62016-11-22 09:44:03 -05002187 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002188 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2189 case Token::MINUS:
Ethan Nicholas0df21132018-07-10 09:37:51 -04002190 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2191 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2192 SkASSERT(b.fLeft->fType == b.fRight->fType);
2193 return this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2194 SpvOpFSub, SpvOpISub, out);
2195 }
Greg Daniel64773e62016-11-22 09:44:03 -05002196 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002197 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2198 case Token::STAR:
Greg Daniel64773e62016-11-22 09:44:03 -05002199 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002200 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002201 // matrix multiply
2202 SpvId result = this->nextId();
2203 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2204 lhs, rhs, out);
2205 return result;
2206 }
Greg Daniel64773e62016-11-22 09:44:03 -05002207 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002208 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2209 case Token::SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002210 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002211 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002212 case Token::PERCENT:
2213 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2214 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002215 case Token::SHL:
2216 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2217 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2218 SpvOpUndef, out);
2219 case Token::SHR:
2220 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2221 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2222 SpvOpUndef, out);
2223 case Token::BITWISEAND:
2224 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2225 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
2226 case Token::BITWISEOR:
2227 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2228 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
2229 case Token::BITWISEXOR:
2230 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2231 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002232 case Token::PLUSEQ: {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002233 SpvId result;
2234 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2235 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2236 SkASSERT(b.fLeft->fType == b.fRight->fType);
2237 result = this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2238 SpvOpFAdd, SpvOpIAdd, out);
2239 }
2240 else {
2241 result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002242 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002243 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002244 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002245 lvalue->store(result, out);
2246 return result;
2247 }
2248 case Token::MINUSEQ: {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002249 SpvId result;
2250 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2251 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2252 SkASSERT(b.fLeft->fType == b.fRight->fType);
2253 result = this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2254 SpvOpFSub, SpvOpISub, out);
2255 }
2256 else {
2257 result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002258 SpvOpISub, SpvOpISub, SpvOpUndef, out);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002259 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002260 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002261 lvalue->store(result, out);
2262 return result;
2263 }
2264 case Token::STAREQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002265 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002266 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002267 // matrix multiply
2268 SpvId result = this->nextId();
2269 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2270 lhs, rhs, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002271 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002272 lvalue->store(result, out);
2273 return result;
2274 }
Greg Daniel64773e62016-11-22 09:44:03 -05002275 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002276 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002277 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002278 lvalue->store(result, out);
2279 return result;
2280 }
2281 case Token::SLASHEQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002282 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002283 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002284 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002285 lvalue->store(result, out);
2286 return result;
2287 }
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002288 case Token::PERCENTEQ: {
2289 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2290 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002291 SkASSERT(lvalue);
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002292 lvalue->store(result, out);
2293 return result;
2294 }
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002295 case Token::SHLEQ: {
2296 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2297 SpvOpUndef, SpvOpShiftLeftLogical,
2298 SpvOpShiftLeftLogical, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002299 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002300 lvalue->store(result, out);
2301 return result;
2302 }
2303 case Token::SHREQ: {
2304 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2305 SpvOpUndef, SpvOpShiftRightArithmetic,
2306 SpvOpShiftRightLogical, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002307 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002308 lvalue->store(result, out);
2309 return result;
2310 }
2311 case Token::BITWISEANDEQ: {
2312 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2313 SpvOpUndef, SpvOpBitwiseAnd, SpvOpBitwiseAnd,
2314 SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002315 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002316 lvalue->store(result, out);
2317 return result;
2318 }
2319 case Token::BITWISEOREQ: {
2320 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2321 SpvOpUndef, SpvOpBitwiseOr, SpvOpBitwiseOr,
2322 SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002323 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002324 lvalue->store(result, out);
2325 return result;
2326 }
2327 case Token::BITWISEXOREQ: {
2328 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2329 SpvOpUndef, SpvOpBitwiseXor, SpvOpBitwiseXor,
2330 SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002331 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002332 lvalue->store(result, out);
2333 return result;
2334 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002335 default:
ethannicholasb3058bd2016-07-01 08:22:01 -07002336 ABORT("unsupported binary expression: %s", b.description().c_str());
2337 }
2338}
2339
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002340SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002341 SkASSERT(a.fOperator == Token::LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002342 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002343 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2344 SpvId lhs = this->writeExpression(*a.fLeft, out);
2345 SpvId rhsLabel = this->nextId();
2346 SpvId end = this->nextId();
2347 SpvId lhsBlock = fCurrentBlock;
2348 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2349 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2350 this->writeLabel(rhsLabel, out);
2351 SpvId rhs = this->writeExpression(*a.fRight, out);
2352 SpvId rhsBlock = fCurrentBlock;
2353 this->writeInstruction(SpvOpBranch, end, out);
2354 this->writeLabel(end, out);
2355 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002356 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002357 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002358 return result;
2359}
2360
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002361SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002362 SkASSERT(o.fOperator == Token::LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002363 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002364 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2365 SpvId lhs = this->writeExpression(*o.fLeft, out);
2366 SpvId rhsLabel = this->nextId();
2367 SpvId end = this->nextId();
2368 SpvId lhsBlock = fCurrentBlock;
2369 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2370 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2371 this->writeLabel(rhsLabel, out);
2372 SpvId rhs = this->writeExpression(*o.fRight, out);
2373 SpvId rhsBlock = fCurrentBlock;
2374 this->writeInstruction(SpvOpBranch, end, out);
2375 this->writeLabel(end, out);
2376 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002377 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002378 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002379 return result;
2380}
2381
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002382SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002383 SpvId test = this->writeExpression(*t.fTest, out);
Ethan Nicholas0f21c232018-07-23 09:25:40 -04002384 if (t.fIfTrue->fType.columns() == 1 && t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002385 // both true and false are constants, can just use OpSelect
2386 SpvId result = this->nextId();
2387 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2388 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
Greg Daniel64773e62016-11-22 09:44:03 -05002389 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002390 out);
2391 return result;
2392 }
Greg Daniel64773e62016-11-22 09:44:03 -05002393 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002394 // Adreno. Switched to storing the result in a temp variable as glslang does.
2395 SpvId var = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002396 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002397 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002398 SpvId trueLabel = this->nextId();
2399 SpvId falseLabel = this->nextId();
2400 SpvId end = this->nextId();
2401 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2402 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2403 this->writeLabel(trueLabel, out);
2404 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2405 this->writeInstruction(SpvOpBranch, end, out);
2406 this->writeLabel(falseLabel, out);
2407 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2408 this->writeInstruction(SpvOpBranch, end, out);
2409 this->writeLabel(end, out);
2410 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002411 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002412 this->writePrecisionModifier(t.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002413 return result;
2414}
2415
ethannicholasd598f792016-07-25 10:08:54 -07002416std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
Ethan Nicholas024301a2017-11-10 13:49:18 -05002417 if (type.isInteger()) {
Ethan Nicholas00543112018-07-31 09:44:36 -04002418 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002419 }
Ethan Nicholas024301a2017-11-10 13:49:18 -05002420 else if (type.isFloat()) {
Ethan Nicholas00543112018-07-31 09:44:36 -04002421 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002422 } else {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002423 ABORT("math is unsupported on type '%s'", type.name().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002424 }
2425}
2426
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002427SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002428 if (p.fOperator == Token::MINUS) {
2429 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002430 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002431 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002432 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002433 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002434 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002435 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2436 } else {
2437 ABORT("unsupported prefix expression %s", p.description().c_str());
Brian Salomon23356442018-11-30 15:33:19 -05002438 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002439 this->writePrecisionModifier(p.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002440 return result;
2441 }
2442 switch (p.fOperator) {
2443 case Token::PLUS:
2444 return this->writeExpression(*p.fOperand, out);
2445 case Token::PLUSPLUS: {
2446 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002447 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002448 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2449 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002450 out);
2451 lv->store(result, out);
2452 return result;
2453 }
2454 case Token::MINUSMINUS: {
2455 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002456 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002457 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2458 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002459 out);
2460 lv->store(result, out);
2461 return result;
2462 }
ethannicholas5961bc92016-10-12 06:39:56 -07002463 case Token::LOGICALNOT: {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002464 SkASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002465 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002466 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002467 this->writeExpression(*p.fOperand, out), out);
2468 return result;
2469 }
ethannicholas5961bc92016-10-12 06:39:56 -07002470 case Token::BITWISENOT: {
2471 SpvId result = this->nextId();
2472 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2473 this->writeExpression(*p.fOperand, out), out);
2474 return result;
2475 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002476 default:
2477 ABORT("unsupported prefix expression: %s", p.description().c_str());
2478 }
2479}
2480
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002481SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002482 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2483 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002484 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002485 switch (p.fOperator) {
2486 case Token::PLUSPLUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002487 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002488 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2489 lv->store(temp, out);
2490 return result;
2491 }
2492 case Token::MINUSMINUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002493 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002494 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2495 lv->store(temp, out);
2496 return result;
2497 }
2498 default:
2499 ABORT("unsupported postfix expression %s", p.description().c_str());
2500 }
2501}
2502
ethannicholasf789b382016-08-03 12:43:36 -07002503SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002504 if (b.fValue) {
2505 if (fBoolTrue == 0) {
2506 fBoolTrue = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002507 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002508 fConstantBuffer);
2509 }
2510 return fBoolTrue;
2511 } else {
2512 if (fBoolFalse == 0) {
2513 fBoolFalse = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002514 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002515 fConstantBuffer);
2516 }
2517 return fBoolFalse;
2518 }
2519}
2520
ethannicholasf789b382016-08-03 12:43:36 -07002521SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
Ethan Nicholas151a8832019-04-16 12:07:26 -04002522 ConstantType type;
ethannicholasd598f792016-07-25 10:08:54 -07002523 if (i.fType == *fContext.fInt_Type) {
Ethan Nicholas151a8832019-04-16 12:07:26 -04002524 type = ConstantType::kInt;
2525 } else if (i.fType == *fContext.fUInt_Type) {
2526 type = ConstantType::kUInt;
2527 } else if (i.fType == *fContext.fShort_Type) {
2528 type = ConstantType::kShort;
2529 } else if (i.fType == *fContext.fUShort_Type) {
2530 type = ConstantType::kUShort;
ethannicholasb3058bd2016-07-01 08:22:01 -07002531 }
Ethan Nicholas151a8832019-04-16 12:07:26 -04002532 std::pair<ConstantValue, ConstantType> key(i.fValue, type);
2533 auto entry = fNumberConstants.find(key);
2534 if (entry == fNumberConstants.end()) {
2535 SpvId result = this->nextId();
2536 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
2537 fConstantBuffer);
2538 this->writePrecisionModifier(i.fType, result);
2539 fNumberConstants[key] = result;
2540 return result;
2541 }
2542 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002543}
2544
ethannicholasf789b382016-08-03 12:43:36 -07002545SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholase1f55022019-02-05 17:17:40 -05002546 if (f.fType != *fContext.fDouble_Type) {
Ethan Nicholas151a8832019-04-16 12:07:26 -04002547 ConstantType type;
2548 if (f.fType == *fContext.fHalf_Type) {
2549 type = ConstantType::kHalf;
2550 } else {
2551 type = ConstantType::kFloat;
2552 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002553 float value = (float) f.fValue;
Ethan Nicholas151a8832019-04-16 12:07:26 -04002554 std::pair<ConstantValue, ConstantType> key(f.fValue, type);
2555 auto entry = fNumberConstants.find(key);
2556 if (entry == fNumberConstants.end()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002557 SpvId result = this->nextId();
2558 uint32_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002559 SkASSERT(sizeof(bits) == sizeof(value));
ethannicholasb3058bd2016-07-01 08:22:01 -07002560 memcpy(&bits, &value, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002561 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
ethannicholasb3058bd2016-07-01 08:22:01 -07002562 fConstantBuffer);
Ethan Nicholas151a8832019-04-16 12:07:26 -04002563 this->writePrecisionModifier(f.fType, result);
2564 fNumberConstants[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002565 return result;
2566 }
2567 return entry->second;
2568 } else {
Ethan Nicholas151a8832019-04-16 12:07:26 -04002569 std::pair<ConstantValue, ConstantType> key(f.fValue, ConstantType::kDouble);
2570 auto entry = fNumberConstants.find(key);
2571 if (entry == fNumberConstants.end()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002572 SpvId result = this->nextId();
2573 uint64_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002574 SkASSERT(sizeof(bits) == sizeof(f.fValue));
ethannicholasb3058bd2016-07-01 08:22:01 -07002575 memcpy(&bits, &f.fValue, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002576 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002577 bits & 0xffffffff, bits >> 32, fConstantBuffer);
Ethan Nicholas151a8832019-04-16 12:07:26 -04002578 fNumberConstants[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002579 return result;
2580 }
2581 return entry->second;
2582 }
2583}
2584
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002585SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002586 SpvId result = fFunctionMap[&f];
Greg Daniel64773e62016-11-22 09:44:03 -05002587 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002588 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002589 this->writeInstruction(SpvOpName, result, f.fName, fNameBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002590 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002591 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002592 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002593 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002594 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002595 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2596 }
2597 return result;
2598}
2599
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002600SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2601 fVariableBuffer.reset();
ethannicholasb3058bd2016-07-01 08:22:01 -07002602 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2603 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002604 StringStream bodyBuffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04002605 this->writeBlock((Block&) *f.fBody, bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002606 write_stringstream(fVariableBuffer, out);
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002607 if (f.fDeclaration.fName == "main") {
2608 write_stringstream(fGlobalInitializersBuffer, out);
2609 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002610 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002611 if (fCurrentBlock) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002612 if (f.fDeclaration.fReturnType == *fContext.fVoid_Type) {
2613 this->writeInstruction(SpvOpReturn, out);
2614 } else {
2615 this->writeInstruction(SpvOpUnreachable, out);
2616 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002617 }
2618 this->writeInstruction(SpvOpFunctionEnd, out);
2619 return result;
2620}
2621
2622void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2623 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002624 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002625 fDecorationBuffer);
2626 }
2627 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002628 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002629 fDecorationBuffer);
2630 }
2631 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002632 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002633 fDecorationBuffer);
2634 }
2635 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002636 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002637 fDecorationBuffer);
2638 }
Greg Daniel64773e62016-11-22 09:44:03 -05002639 if (layout.fInputAttachmentIndex >= 0) {
2640 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2641 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002642 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002643 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002644 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002645 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002646 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002647 fDecorationBuffer);
2648 }
2649}
2650
2651void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2652 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002653 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002654 layout.fLocation, fDecorationBuffer);
2655 }
2656 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002657 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002658 layout.fBinding, fDecorationBuffer);
2659 }
2660 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002661 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002662 layout.fIndex, fDecorationBuffer);
2663 }
2664 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002665 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002666 layout.fSet, fDecorationBuffer);
2667 }
Greg Daniel64773e62016-11-22 09:44:03 -05002668 if (layout.fInputAttachmentIndex >= 0) {
2669 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2670 layout.fInputAttachmentIndex, fDecorationBuffer);
2671 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002672 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002673 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002674 layout.fBuiltin, fDecorationBuffer);
2675 }
2676}
2677
Ethan Nicholas81d15112018-07-13 12:48:50 -04002678static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2679 switch (m.fLayout.fPrimitive) {
2680 case Layout::kPoints_Primitive:
2681 *outSkInCount = 1;
2682 break;
2683 case Layout::kLines_Primitive:
2684 *outSkInCount = 2;
2685 break;
2686 case Layout::kLinesAdjacency_Primitive:
2687 *outSkInCount = 4;
2688 break;
2689 case Layout::kTriangles_Primitive:
2690 *outSkInCount = 3;
2691 break;
2692 case Layout::kTrianglesAdjacency_Primitive:
2693 *outSkInCount = 6;
2694 break;
2695 default:
2696 return;
2697 }
2698}
2699
ethannicholasf789b382016-08-03 12:43:36 -07002700SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas361941e2017-05-30 15:41:07 -04002701 bool isBuffer = (0 != (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag));
Ethan Nicholas39204fd2017-11-27 13:12:30 -05002702 bool pushConstant = (0 != (intf.fVariable.fModifiers.fLayout.fFlags &
2703 Layout::kPushConstant_Flag));
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002704 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2705 MemoryLayout(MemoryLayout::k430_Standard) :
2706 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002707 SpvId result = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002708 const Type* type = &intf.fVariable.fType;
Greg Daniele6ab9982018-08-22 13:56:32 +00002709 if (fProgram.fInputs.fRTHeight) {
2710 SkASSERT(fRTHeightStructId == (SpvId) -1);
2711 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002712 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002713 fRTHeightStructId = result;
2714 fRTHeightFieldIndex = fields.size();
2715 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002716 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002717 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002718 SpvId typeId;
2719 if (intf.fVariable.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2720 for (const auto& e : fProgram) {
2721 if (e.fKind == ProgramElement::kModifiers_Kind) {
2722 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholas81d15112018-07-13 12:48:50 -04002723 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002724 }
2725 }
2726 typeId = this->getType(Type("sk_in", Type::kArray_Kind, intf.fVariable.fType.componentType(),
2727 fSkInCount), memoryLayout);
2728 } else {
2729 typeId = this->getType(*type, memoryLayout);
2730 }
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002731 if (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag) {
2732 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002733 } else if (intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
2734 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002735 }
ethannicholasd598f792016-07-25 10:08:54 -07002736 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002737 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002738 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002739 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002740 Layout layout = intf.fVariable.fModifiers.fLayout;
2741 if (intf.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
2742 layout.fSet = 0;
2743 }
2744 this->writeLayout(layout, result);
ethannicholasd598f792016-07-25 10:08:54 -07002745 fVariableMap[&intf.fVariable] = result;
Greg Daniele6ab9982018-08-22 13:56:32 +00002746 if (fProgram.fInputs.fRTHeight) {
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002747 delete type;
2748 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002749 return result;
2750}
2751
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002752void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002753 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2754}
2755
2756void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2757 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002758 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2759 }
2760}
2761
ethannicholas5961bc92016-10-12 06:39:56 -07002762#define BUILTIN_IGNORE 9999
Greg Daniel64773e62016-11-22 09:44:03 -05002763void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002764 OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002765 for (size_t i = 0; i < decl.fVars.size(); i++) {
2766 if (decl.fVars[i]->fKind == Statement::kNop_Kind) {
2767 continue;
2768 }
2769 const VarDeclaration& varDecl = (VarDeclaration&) *decl.fVars[i];
2770 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002771 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2772 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002773 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002774 Modifiers::kWriteOnly_Flag |
2775 Modifiers::kCoherent_Flag |
2776 Modifiers::kVolatile_Flag |
2777 Modifiers::kRestrict_Flag)));
ethannicholas5961bc92016-10-12 06:39:56 -07002778 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2779 continue;
2780 }
2781 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2782 kind != Program::kFragment_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002783 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
ethannicholas5961bc92016-10-12 06:39:56 -07002784 continue;
2785 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05002786 if (!var->fReadCount && !var->fWriteCount &&
ethannicholas14fe8cc2016-09-07 13:37:16 -07002787 !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
2788 Modifiers::kOut_Flag |
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002789 Modifiers::kUniform_Flag |
2790 Modifiers::kBuffer_Flag))) {
ethannicholasd598f792016-07-25 10:08:54 -07002791 // variable is dead and not an input / output var (the Vulkan debug layers complain if
2792 // we elide an interface var, even if it's dead)
ethannicholasb3058bd2016-07-01 08:22:01 -07002793 continue;
2794 }
2795 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002796 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002797 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002798 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002799 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002800 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
2801 if (var->fType.kind() == Type::kSampler_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002802 storageClass = SpvStorageClassUniformConstant;
2803 } else {
2804 storageClass = SpvStorageClassUniform;
2805 }
2806 } else {
2807 storageClass = SpvStorageClassPrivate;
2808 }
2809 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002810 fVariableMap[var] = id;
Ethan Nicholas5226b772018-05-03 16:20:41 -04002811 SpvId type;
2812 if (var->fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2813 type = this->getPointerType(Type("sk_in", Type::kArray_Kind,
2814 var->fType.componentType(), fSkInCount),
2815 storageClass);
2816 } else {
2817 type = this->getPointerType(var->fType, storageClass);
2818 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002819 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002820 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002821 this->writePrecisionModifier(var->fType, id);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002822 if (varDecl.fValue) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002823 SkASSERT(!fCurrentBlock);
ethannicholasf789b382016-08-03 12:43:36 -07002824 fCurrentBlock = -1;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002825 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002826 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002827 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002828 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002829 this->writeLayout(var->fModifiers.fLayout, id);
Ethan Nicholas45b0f152017-07-24 14:36:40 -04002830 if (var->fModifiers.fFlags & Modifiers::kFlat_Flag) {
2831 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2832 }
2833 if (var->fModifiers.fFlags & Modifiers::kNoPerspective_Flag) {
2834 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2835 fDecorationBuffer);
2836 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002837 }
2838}
2839
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002840void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002841 for (const auto& stmt : decl.fVars) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002842 SkASSERT(stmt->fKind == Statement::kVarDeclaration_Kind);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002843 VarDeclaration& varDecl = (VarDeclaration&) *stmt;
2844 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002845 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2846 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002847 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002848 Modifiers::kWriteOnly_Flag |
2849 Modifiers::kCoherent_Flag |
2850 Modifiers::kVolatile_Flag |
2851 Modifiers::kRestrict_Flag)));
ethannicholasb3058bd2016-07-01 08:22:01 -07002852 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002853 fVariableMap[var] = id;
2854 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002855 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002856 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002857 if (varDecl.fValue) {
2858 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002859 this->writeInstruction(SpvOpStore, id, value, out);
2860 }
2861 }
2862}
2863
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002864void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002865 switch (s.fKind) {
Ethan Nicholascb670962017-04-20 19:31:52 -04002866 case Statement::kNop_Kind:
2867 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002868 case Statement::kBlock_Kind:
2869 this->writeBlock((Block&) s, out);
2870 break;
2871 case Statement::kExpression_Kind:
2872 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2873 break;
Greg Daniel64773e62016-11-22 09:44:03 -05002874 case Statement::kReturn_Kind:
ethannicholasb3058bd2016-07-01 08:22:01 -07002875 this->writeReturnStatement((ReturnStatement&) s, out);
2876 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002877 case Statement::kVarDeclarations_Kind:
2878 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002879 break;
2880 case Statement::kIf_Kind:
2881 this->writeIfStatement((IfStatement&) s, out);
2882 break;
2883 case Statement::kFor_Kind:
2884 this->writeForStatement((ForStatement&) s, out);
2885 break;
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002886 case Statement::kWhile_Kind:
2887 this->writeWhileStatement((WhileStatement&) s, out);
2888 break;
2889 case Statement::kDo_Kind:
2890 this->writeDoStatement((DoStatement&) s, out);
2891 break;
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002892 case Statement::kSwitch_Kind:
2893 this->writeSwitchStatement((SwitchStatement&) s, out);
2894 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002895 case Statement::kBreak_Kind:
2896 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2897 break;
2898 case Statement::kContinue_Kind:
2899 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2900 break;
2901 case Statement::kDiscard_Kind:
2902 this->writeInstruction(SpvOpKill, out);
2903 break;
2904 default:
2905 ABORT("unsupported statement: %s", s.description().c_str());
2906 }
2907}
2908
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002909void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002910 for (size_t i = 0; i < b.fStatements.size(); i++) {
2911 this->writeStatement(*b.fStatements[i], out);
2912 }
2913}
2914
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002915void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002916 SpvId test = this->writeExpression(*stmt.fTest, out);
2917 SpvId ifTrue = this->nextId();
2918 SpvId ifFalse = this->nextId();
2919 if (stmt.fIfFalse) {
2920 SpvId end = this->nextId();
2921 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2922 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2923 this->writeLabel(ifTrue, out);
2924 this->writeStatement(*stmt.fIfTrue, out);
2925 if (fCurrentBlock) {
2926 this->writeInstruction(SpvOpBranch, end, out);
2927 }
2928 this->writeLabel(ifFalse, out);
2929 this->writeStatement(*stmt.fIfFalse, out);
2930 if (fCurrentBlock) {
2931 this->writeInstruction(SpvOpBranch, end, out);
2932 }
2933 this->writeLabel(end, out);
2934 } else {
2935 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2936 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2937 this->writeLabel(ifTrue, out);
2938 this->writeStatement(*stmt.fIfTrue, out);
2939 if (fCurrentBlock) {
2940 this->writeInstruction(SpvOpBranch, ifFalse, out);
2941 }
2942 this->writeLabel(ifFalse, out);
2943 }
2944}
2945
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002946void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002947 if (f.fInitializer) {
2948 this->writeStatement(*f.fInitializer, out);
2949 }
2950 SpvId header = this->nextId();
2951 SpvId start = this->nextId();
2952 SpvId body = this->nextId();
2953 SpvId next = this->nextId();
2954 fContinueTarget.push(next);
2955 SpvId end = this->nextId();
2956 fBreakTarget.push(end);
2957 this->writeInstruction(SpvOpBranch, header, out);
2958 this->writeLabel(header, out);
2959 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002960 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002961 this->writeLabel(start, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002962 if (f.fTest) {
2963 SpvId test = this->writeExpression(*f.fTest, out);
2964 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2965 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002966 this->writeLabel(body, out);
2967 this->writeStatement(*f.fStatement, out);
2968 if (fCurrentBlock) {
2969 this->writeInstruction(SpvOpBranch, next, out);
2970 }
2971 this->writeLabel(next, out);
2972 if (f.fNext) {
2973 this->writeExpression(*f.fNext, out);
2974 }
2975 this->writeInstruction(SpvOpBranch, header, out);
2976 this->writeLabel(end, out);
2977 fBreakTarget.pop();
2978 fContinueTarget.pop();
2979}
2980
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002981void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002982 SpvId header = this->nextId();
2983 SpvId start = this->nextId();
2984 SpvId body = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04002985 SpvId continueTarget = this->nextId();
2986 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002987 SpvId end = this->nextId();
2988 fBreakTarget.push(end);
2989 this->writeInstruction(SpvOpBranch, header, out);
2990 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04002991 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002992 this->writeInstruction(SpvOpBranch, start, out);
2993 this->writeLabel(start, out);
2994 SpvId test = this->writeExpression(*w.fTest, out);
2995 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2996 this->writeLabel(body, out);
2997 this->writeStatement(*w.fStatement, out);
2998 if (fCurrentBlock) {
Ethan Nicholas0d997662019-04-08 09:46:01 -04002999 this->writeInstruction(SpvOpBranch, continueTarget, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003000 }
Ethan Nicholas0d997662019-04-08 09:46:01 -04003001 this->writeLabel(continueTarget, out);
3002 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003003 this->writeLabel(end, out);
3004 fBreakTarget.pop();
3005 fContinueTarget.pop();
3006}
3007
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003008void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003009 // We believe the do loop code below will work, but Skia doesn't actually use them and
3010 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
3011 // the time being, we just fail with an error due to the lack of testing. If you encounter this
3012 // message, simply remove the error call below to see whether our do loop support actually
3013 // works.
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003014 fErrors.error(d.fOffset, "internal error: do loop support has been disabled in SPIR-V, see "
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003015 "SkSLSPIRVCodeGenerator.cpp for details");
3016
3017 SpvId header = this->nextId();
3018 SpvId start = this->nextId();
3019 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003020 SpvId continueTarget = this->nextId();
3021 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003022 SpvId end = this->nextId();
3023 fBreakTarget.push(end);
3024 this->writeInstruction(SpvOpBranch, header, out);
3025 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003026 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003027 this->writeInstruction(SpvOpBranch, start, out);
3028 this->writeLabel(start, out);
3029 this->writeStatement(*d.fStatement, out);
3030 if (fCurrentBlock) {
3031 this->writeInstruction(SpvOpBranch, next, out);
3032 }
3033 this->writeLabel(next, out);
3034 SpvId test = this->writeExpression(*d.fTest, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003035 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
3036 this->writeLabel(continueTarget, out);
3037 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003038 this->writeLabel(end, out);
3039 fBreakTarget.pop();
3040 fContinueTarget.pop();
3041}
3042
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003043void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
3044 SpvId value = this->writeExpression(*s.fValue, out);
3045 std::vector<SpvId> labels;
3046 SpvId end = this->nextId();
3047 SpvId defaultLabel = end;
3048 fBreakTarget.push(end);
3049 int size = 3;
3050 for (const auto& c : s.fCases) {
3051 SpvId label = this->nextId();
3052 labels.push_back(label);
3053 if (c->fValue) {
3054 size += 2;
3055 } else {
3056 defaultLabel = label;
3057 }
3058 }
3059 labels.push_back(end);
3060 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3061 this->writeOpCode(SpvOpSwitch, size, out);
3062 this->writeWord(value, out);
3063 this->writeWord(defaultLabel, out);
3064 for (size_t i = 0; i < s.fCases.size(); ++i) {
3065 if (!s.fCases[i]->fValue) {
3066 continue;
3067 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003068 SkASSERT(s.fCases[i]->fValue->fKind == Expression::kIntLiteral_Kind);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003069 this->writeWord(((IntLiteral&) *s.fCases[i]->fValue).fValue, out);
3070 this->writeWord(labels[i], out);
3071 }
3072 for (size_t i = 0; i < s.fCases.size(); ++i) {
3073 this->writeLabel(labels[i], out);
3074 for (const auto& stmt : s.fCases[i]->fStatements) {
3075 this->writeStatement(*stmt, out);
3076 }
3077 if (fCurrentBlock) {
3078 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3079 }
3080 }
3081 this->writeLabel(end, out);
3082 fBreakTarget.pop();
3083}
3084
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003085void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003086 if (r.fExpression) {
Greg Daniel64773e62016-11-22 09:44:03 -05003087 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003088 out);
3089 } else {
3090 this->writeInstruction(SpvOpReturn, out);
3091 }
3092}
3093
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003094void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003095 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003096 int invocations = 1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003097 for (const auto& e : fProgram) {
3098 if (e.fKind == ProgramElement::kModifiers_Kind) {
3099 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003100 if (m.fFlags & Modifiers::kIn_Flag) {
3101 if (m.fLayout.fInvocations != -1) {
3102 invocations = m.fLayout.fInvocations;
3103 }
3104 SpvId input;
3105 switch (m.fLayout.fPrimitive) {
3106 case Layout::kPoints_Primitive:
3107 input = SpvExecutionModeInputPoints;
3108 break;
3109 case Layout::kLines_Primitive:
3110 input = SpvExecutionModeInputLines;
3111 break;
3112 case Layout::kLinesAdjacency_Primitive:
3113 input = SpvExecutionModeInputLinesAdjacency;
3114 break;
3115 case Layout::kTriangles_Primitive:
3116 input = SpvExecutionModeTriangles;
3117 break;
3118 case Layout::kTrianglesAdjacency_Primitive:
3119 input = SpvExecutionModeInputTrianglesAdjacency;
3120 break;
3121 default:
3122 input = 0;
3123 break;
3124 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003125 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003126 if (input) {
3127 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3128 }
3129 } else if (m.fFlags & Modifiers::kOut_Flag) {
3130 SpvId output;
3131 switch (m.fLayout.fPrimitive) {
3132 case Layout::kPoints_Primitive:
3133 output = SpvExecutionModeOutputPoints;
3134 break;
3135 case Layout::kLineStrip_Primitive:
3136 output = SpvExecutionModeOutputLineStrip;
3137 break;
3138 case Layout::kTriangleStrip_Primitive:
3139 output = SpvExecutionModeOutputTriangleStrip;
3140 break;
3141 default:
3142 output = 0;
3143 break;
3144 }
3145 if (output) {
3146 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3147 }
3148 if (m.fLayout.fMaxVertices != -1) {
3149 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3150 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3151 out);
3152 }
3153 }
3154 }
3155 }
3156 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3157 invocations, out);
3158}
3159
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003160void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003161 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003162 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003163 std::set<SpvId> interfaceVars;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003164 // assign IDs to functions, determine sk_in size
3165 int skInSize = -1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003166 for (const auto& e : program) {
3167 switch (e.fKind) {
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003168 case ProgramElement::kFunction_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003169 FunctionDefinition& f = (FunctionDefinition&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003170 fFunctionMap[&f.fDeclaration] = this->nextId();
3171 break;
3172 }
3173 case ProgramElement::kModifiers_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003174 Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003175 if (m.fFlags & Modifiers::kIn_Flag) {
3176 switch (m.fLayout.fPrimitive) {
3177 case Layout::kPoints_Primitive: // break
3178 case Layout::kLines_Primitive:
3179 skInSize = 1;
3180 break;
3181 case Layout::kLinesAdjacency_Primitive: // break
3182 skInSize = 2;
3183 break;
3184 case Layout::kTriangles_Primitive: // break
3185 case Layout::kTrianglesAdjacency_Primitive:
3186 skInSize = 3;
3187 break;
3188 default:
3189 break;
3190 }
3191 }
3192 break;
3193 }
3194 default:
3195 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003196 }
3197 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003198 for (const auto& e : program) {
3199 if (e.fKind == ProgramElement::kInterfaceBlock_Kind) {
3200 InterfaceBlock& intf = (InterfaceBlock&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003201 if (SK_IN_BUILTIN == intf.fVariable.fModifiers.fLayout.fBuiltin) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003202 SkASSERT(skInSize != -1);
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003203 intf.fSizes.emplace_back(new IntLiteral(fContext, -1, skInSize));
3204 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003205 SpvId id = this->writeInterfaceBlock(intf);
Ethan Nicholas16c11962018-03-16 12:20:54 -04003206 if (((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
3207 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) &&
3208 intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003209 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003210 }
3211 }
3212 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003213 for (const auto& e : program) {
3214 if (e.fKind == ProgramElement::kVar_Kind) {
3215 this->writeGlobalVars(program.fKind, ((VarDeclarations&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003216 }
3217 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003218 for (const auto& e : program) {
3219 if (e.fKind == ProgramElement::kFunction_Kind) {
3220 this->writeFunction(((FunctionDefinition&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003221 }
3222 }
ethannicholasd598f792016-07-25 10:08:54 -07003223 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003224 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07003225 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003226 main = entry.first;
3227 }
3228 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003229 SkASSERT(main);
ethannicholasb3058bd2016-07-01 08:22:01 -07003230 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003231 const Variable* var = entry.first;
Greg Daniel64773e62016-11-22 09:44:03 -05003232 if (var->fStorage == Variable::kGlobal_Storage &&
Ethan Nicholas16c11962018-03-16 12:20:54 -04003233 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
Ethan Nicholasd23c8192018-09-26 17:01:24 -04003234 (var->fModifiers.fFlags & Modifiers::kOut_Flag))) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003235 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003236 }
3237 }
3238 this->writeCapabilities(out);
3239 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3240 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003241 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->fName.fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003242 (int32_t) interfaceVars.size(), out);
3243 switch (program.fKind) {
3244 case Program::kVertex_Kind:
3245 this->writeWord(SpvExecutionModelVertex, out);
3246 break;
3247 case Program::kFragment_Kind:
3248 this->writeWord(SpvExecutionModelFragment, out);
3249 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003250 case Program::kGeometry_Kind:
3251 this->writeWord(SpvExecutionModelGeometry, out);
3252 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003253 default:
3254 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003255 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003256 SpvId entryPoint = fFunctionMap[main];
3257 this->writeWord(entryPoint, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003258 this->writeString(main->fName.fChars, main->fName.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003259 for (int var : interfaceVars) {
3260 this->writeWord(var, out);
3261 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003262 if (program.fKind == Program::kGeometry_Kind) {
3263 this->writeGeometryShaderExecutionMode(entryPoint, out);
3264 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003265 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003266 this->writeInstruction(SpvOpExecutionMode,
3267 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003268 SpvExecutionModeOriginUpperLeft,
3269 out);
3270 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003271 for (const auto& e : program) {
3272 if (e.fKind == ProgramElement::kExtension_Kind) {
3273 this->writeInstruction(SpvOpSourceExtension, ((Extension&) e).fName.c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003274 }
3275 }
Greg Daniel64773e62016-11-22 09:44:03 -05003276
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003277 write_stringstream(fExtraGlobalsBuffer, out);
3278 write_stringstream(fNameBuffer, out);
3279 write_stringstream(fDecorationBuffer, out);
3280 write_stringstream(fConstantBuffer, out);
3281 write_stringstream(fExternalFunctionsBuffer, out);
3282 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003283}
3284
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003285bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003286 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003287 this->writeWord(SpvMagicNumber, *fOut);
3288 this->writeWord(SpvVersion, *fOut);
3289 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003290 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003291 this->writeInstructions(fProgram, buffer);
3292 this->writeWord(fIdCount, *fOut);
3293 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003294 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003295 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003296}
3297
3298}