blob: 6dfc2e37e9f097c62a50f06cc1774c49adc9c981 [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);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400101 fIntrinsicMap[String("dFdy")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400102 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400103 fIntrinsicMap[String("dFdy")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400104 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400105 fIntrinsicMap[String("texture")] = SPECIAL(Texture);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400106 fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
Greg Daniel64773e62016-11-22 09:44:03 -0500107
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400108 fIntrinsicMap[String("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400109 SpvOpUndef, SpvOpUndef, SpvOpAny);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400110 fIntrinsicMap[String("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400111 SpvOpUndef, SpvOpUndef, SpvOpAll);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400112 fIntrinsicMap[String("equal")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400113 SpvOpFOrdEqual, SpvOpIEqual,
114 SpvOpIEqual, SpvOpLogicalEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400115 fIntrinsicMap[String("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400116 SpvOpFOrdNotEqual, SpvOpINotEqual,
117 SpvOpINotEqual,
118 SpvOpLogicalNotEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400119 fIntrinsicMap[String("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500120 SpvOpFOrdLessThan, SpvOpSLessThan,
121 SpvOpULessThan, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400122 fIntrinsicMap[String("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500123 SpvOpFOrdLessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400124 SpvOpSLessThanEqual,
125 SpvOpULessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400126 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400127 fIntrinsicMap[String("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500128 SpvOpFOrdGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400129 SpvOpSGreaterThan,
130 SpvOpUGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400131 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400132 fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500133 SpvOpFOrdGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400134 SpvOpSGreaterThanEqual,
135 SpvOpUGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400136 SpvOpUndef);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400137 fIntrinsicMap[String("EmitVertex")] = ALL_SPIRV(EmitVertex);
138 fIntrinsicMap[String("EndPrimitive")] = ALL_SPIRV(EndPrimitive);
ethannicholasb3058bd2016-07-01 08:22:01 -0700139// interpolateAt* not yet supported...
140}
141
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400142void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700143 out.write((const char*) &word, sizeof(word));
ethannicholasb3058bd2016-07-01 08:22:01 -0700144}
145
ethannicholasd598f792016-07-25 10:08:54 -0700146static bool is_float(const Context& context, const Type& type) {
Ethan Nicholas0df21132018-07-10 09:37:51 -0400147 if (type.columns() > 1) {
ethannicholasd598f792016-07-25 10:08:54 -0700148 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700149 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400150 return type == *context.fFloat_Type || type == *context.fHalf_Type ||
151 type == *context.fDouble_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700152}
153
ethannicholasd598f792016-07-25 10:08:54 -0700154static bool is_signed(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700155 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700156 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700157 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400158 return type == *context.fInt_Type || type == *context.fShort_Type ||
159 type == *context.fByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700160}
161
ethannicholasd598f792016-07-25 10:08:54 -0700162static bool is_unsigned(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700163 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700164 return is_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700165 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400166 return type == *context.fUInt_Type || type == *context.fUShort_Type ||
167 type == *context.fUByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700168}
169
ethannicholasd598f792016-07-25 10:08:54 -0700170static bool is_bool(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700171 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700172 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700173 }
ethannicholasd598f792016-07-25 10:08:54 -0700174 return type == *context.fBool_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700175}
176
ethannicholasd598f792016-07-25 10:08:54 -0700177static bool is_out(const Variable& var) {
178 return (var.fModifiers.fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700179}
180
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400181void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400182 SkASSERT(opCode != SpvOpLoad || &out != &fConstantBuffer);
183 SkASSERT(opCode != SpvOpUndef);
ethannicholasb3058bd2016-07-01 08:22:01 -0700184 switch (opCode) {
185 case SpvOpReturn: // fall through
186 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700187 case SpvOpKill: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700188 case SpvOpBranch: // fall through
189 case SpvOpBranchConditional:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400190 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700191 fCurrentBlock = 0;
192 break;
193 case SpvOpConstant: // fall through
194 case SpvOpConstantTrue: // fall through
195 case SpvOpConstantFalse: // fall through
196 case SpvOpConstantComposite: // fall through
197 case SpvOpTypeVoid: // fall through
198 case SpvOpTypeInt: // fall through
199 case SpvOpTypeFloat: // fall through
200 case SpvOpTypeBool: // fall through
201 case SpvOpTypeVector: // fall through
202 case SpvOpTypeMatrix: // fall through
203 case SpvOpTypeArray: // fall through
204 case SpvOpTypePointer: // fall through
205 case SpvOpTypeFunction: // fall through
206 case SpvOpTypeRuntimeArray: // fall through
207 case SpvOpTypeStruct: // fall through
208 case SpvOpTypeImage: // fall through
209 case SpvOpTypeSampledImage: // fall through
210 case SpvOpVariable: // fall through
211 case SpvOpFunction: // fall through
212 case SpvOpFunctionParameter: // fall through
213 case SpvOpFunctionEnd: // fall through
214 case SpvOpExecutionMode: // fall through
215 case SpvOpMemoryModel: // fall through
216 case SpvOpCapability: // fall through
217 case SpvOpExtInstImport: // fall through
218 case SpvOpEntryPoint: // fall through
219 case SpvOpSource: // fall through
220 case SpvOpSourceExtension: // fall through
221 case SpvOpName: // fall through
222 case SpvOpMemberName: // fall through
223 case SpvOpDecorate: // fall through
224 case SpvOpMemberDecorate:
225 break;
226 default:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400227 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700228 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700229 this->writeWord((length << 16) | opCode, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700230}
231
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400232void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700233 fCurrentBlock = label;
234 this->writeInstruction(SpvOpLabel, label, out);
235}
236
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400237void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700238 this->writeOpCode(opCode, 1, out);
239}
240
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400241void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700242 this->writeOpCode(opCode, 2, out);
243 this->writeWord(word1, out);
244}
245
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700246void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputStream& out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400247 out.write(string, length);
ethannicholasb3058bd2016-07-01 08:22:01 -0700248 switch (length % 4) {
249 case 1:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500250 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700251 // fall through
252 case 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500253 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700254 // fall through
255 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500256 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700257 break;
258 default:
259 this->writeWord(0, out);
260 }
261}
262
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700263void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out) {
264 this->writeOpCode(opCode, 1 + (string.fLength + 4) / 4, out);
265 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700266}
267
268
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700269void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400270 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700271 this->writeOpCode(opCode, 2 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700272 this->writeWord(word1, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700273 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700274}
275
Greg Daniel64773e62016-11-22 09:44:03 -0500276void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700277 StringFragment string, OutputStream& out) {
278 this->writeOpCode(opCode, 3 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700279 this->writeWord(word1, out);
280 this->writeWord(word2, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700281 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700282}
283
Greg Daniel64773e62016-11-22 09:44:03 -0500284void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400285 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700286 this->writeOpCode(opCode, 3, out);
287 this->writeWord(word1, out);
288 this->writeWord(word2, out);
289}
290
Greg Daniel64773e62016-11-22 09:44:03 -0500291void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400292 int32_t word3, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700293 this->writeOpCode(opCode, 4, out);
294 this->writeWord(word1, out);
295 this->writeWord(word2, out);
296 this->writeWord(word3, out);
297}
298
Greg Daniel64773e62016-11-22 09:44:03 -0500299void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400300 int32_t word3, int32_t word4, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700301 this->writeOpCode(opCode, 5, out);
302 this->writeWord(word1, out);
303 this->writeWord(word2, out);
304 this->writeWord(word3, out);
305 this->writeWord(word4, out);
306}
307
Greg Daniel64773e62016-11-22 09:44:03 -0500308void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
309 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400310 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700311 this->writeOpCode(opCode, 6, out);
312 this->writeWord(word1, out);
313 this->writeWord(word2, out);
314 this->writeWord(word3, out);
315 this->writeWord(word4, out);
316 this->writeWord(word5, out);
317}
318
Greg Daniel64773e62016-11-22 09:44:03 -0500319void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700320 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400321 int32_t word6, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700322 this->writeOpCode(opCode, 7, out);
323 this->writeWord(word1, out);
324 this->writeWord(word2, out);
325 this->writeWord(word3, out);
326 this->writeWord(word4, out);
327 this->writeWord(word5, out);
328 this->writeWord(word6, out);
329}
330
Greg Daniel64773e62016-11-22 09:44:03 -0500331void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700332 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400333 int32_t word6, int32_t word7, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700334 this->writeOpCode(opCode, 8, out);
335 this->writeWord(word1, out);
336 this->writeWord(word2, out);
337 this->writeWord(word3, out);
338 this->writeWord(word4, out);
339 this->writeWord(word5, out);
340 this->writeWord(word6, out);
341 this->writeWord(word7, out);
342}
343
Greg Daniel64773e62016-11-22 09:44:03 -0500344void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700345 int32_t word3, int32_t word4, int32_t word5,
346 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400347 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700348 this->writeOpCode(opCode, 9, out);
349 this->writeWord(word1, out);
350 this->writeWord(word2, out);
351 this->writeWord(word3, out);
352 this->writeWord(word4, out);
353 this->writeWord(word5, out);
354 this->writeWord(word6, out);
355 this->writeWord(word7, out);
356 this->writeWord(word8, out);
357}
358
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400359void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700360 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
361 if (fCapabilities & bit) {
362 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
363 }
364 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400365 if (fProgram.fKind == Program::kGeometry_Kind) {
366 this->writeInstruction(SpvOpCapability, SpvCapabilityGeometry, out);
367 }
Ethan Nicholas81d15112018-07-13 12:48:50 -0400368 else {
369 this->writeInstruction(SpvOpCapability, SpvCapabilityShader, out);
370 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700371}
372
373SpvId SPIRVCodeGenerator::nextId() {
374 return fIdCount++;
375}
376
Ethan Nicholas19671772016-11-28 16:30:17 -0500377void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
378 SpvId resultId) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700379 this->writeInstruction(SpvOpName, resultId, type.name().c_str(), fNameBuffer);
380 // go ahead and write all of the field types, so we don't inadvertently write them while we're
381 // in the middle of writing the struct instruction
382 std::vector<SpvId> types;
383 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500384 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700385 }
386 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
387 this->writeWord(resultId, fConstantBuffer);
388 for (SpvId id : types) {
389 this->writeWord(id, fConstantBuffer);
390 }
391 size_t offset = 0;
392 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500393 size_t size = memoryLayout.size(*type.fields()[i].fType);
394 size_t alignment = memoryLayout.alignment(*type.fields()[i].fType);
395 const Layout& fieldLayout = type.fields()[i].fModifiers.fLayout;
396 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 Nicholas941e7e22016-12-12 15:33:30 -0500399 "offset of field '" + type.fields()[i].fName + "' must be at "
400 "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 Nicholas941e7e22016-12-12 15:33:30 -0500404 "offset of field '" + type.fields()[i].fName + "' must be a multiple"
405 " 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 Nicholas5b5f0962017-09-11 13:50:14 -0700414 this->writeInstruction(SpvOpMemberName, resultId, i, type.fields()[i].fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500415 this->writeLayout(fieldLayout, resultId, i);
ethannicholasb3058bd2016-07-01 08:22:01 -0700416 if (type.fields()[i].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 }
ethannicholas0730be72016-09-01 07:59:02 -0700420 if (type.fields()[i].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 Nicholas19671772016-11-28 16:30:17 -0500424 (SpvId) memoryLayout.stride(*type.fields()[i].fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800425 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700426 }
427 offset += size;
ethannicholas0730be72016-09-01 07:59:02 -0700428 Type::Kind kind = type.fields()[i].fType->kind();
ethannicholasb3058bd2016-07-01 08:22:01 -0700429 if ((kind == Type::kArray_Kind || kind == Type::kStruct_Kind) && offset % alignment != 0) {
430 offset += alignment - offset % alignment;
431 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700432 }
433}
434
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400435Type SPIRVCodeGenerator::getActualType(const Type& type) {
436 if (type == *fContext.fHalf_Type) {
437 return *fContext.fFloat_Type;
438 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400439 if (type == *fContext.fShort_Type || type == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400440 return *fContext.fInt_Type;
441 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400442 if (type == *fContext.fUShort_Type || type == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400443 return *fContext.fUInt_Type;
444 }
445 if (type.kind() == Type::kMatrix_Kind || type.kind() == Type::kVector_Kind) {
446 if (type.componentType() == *fContext.fHalf_Type) {
447 return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
448 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400449 if (type.componentType() == *fContext.fShort_Type ||
450 type.componentType() == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400451 return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
452 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400453 if (type.componentType() == *fContext.fUShort_Type ||
454 type.componentType() == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400455 return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
456 }
457 }
458 return type;
459}
460
ethannicholasb3058bd2016-07-01 08:22:01 -0700461SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800462 return this->getType(type, fDefaultLayout);
463}
464
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400465SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
466 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400467 String key = type.name() + to_string((int) layout.fStd);
ethannicholas8ac838d2016-11-22 08:39:36 -0800468 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700469 if (entry == fTypeMap.end()) {
470 SpvId result = this->nextId();
471 switch (type.kind()) {
472 case Type::kScalar_Kind:
ethannicholasd598f792016-07-25 10:08:54 -0700473 if (type == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700474 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -0700475 } else if (type == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700476 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -0700477 } else if (type == *fContext.fUInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700478 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -0700479 } else if (type == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700480 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -0700481 } else if (type == *fContext.fDouble_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700482 this->writeInstruction(SpvOpTypeFloat, result, 64, fConstantBuffer);
483 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400484 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700485 }
486 break;
487 case Type::kVector_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500488 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800489 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700490 type.columns(), fConstantBuffer);
491 break;
492 case Type::kMatrix_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500493 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800494 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700495 type.columns(), fConstantBuffer);
496 break;
497 case Type::kStruct_Kind:
ethannicholas8ac838d2016-11-22 08:39:36 -0800498 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700499 break;
500 case Type::kArray_Kind: {
501 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700502 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500503 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800504 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700505 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500506 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400507 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800508 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700509 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400510 SkASSERT(false); // we shouldn't have any runtime-sized arrays right now
Greg Daniel64773e62016-11-22 09:44:03 -0500511 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800512 this->getType(type.componentType(), layout),
513 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400514 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
515 (int32_t) layout.stride(type),
516 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700517 }
518 break;
519 }
520 case Type::kSampler_Kind: {
Greg Daniel64773e62016-11-22 09:44:03 -0500521 SpvId image = result;
522 if (SpvDimSubpassData != type.dimensions()) {
523 image = this->nextId();
524 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400525 if (SpvDimBuffer == type.dimensions()) {
526 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
527 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800528 this->writeInstruction(SpvOpTypeImage, image,
529 this->getType(*fContext.fFloat_Type, layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700530 type.dimensions(), type.isDepth(), type.isArrayed(),
Greg Daniel64773e62016-11-22 09:44:03 -0500531 type.isMultisampled(), type.isSampled() ? 1 : 2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700532 SpvImageFormatUnknown, fConstantBuffer);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400533 fImageTypeMap[key] = image;
Greg Daniel64773e62016-11-22 09:44:03 -0500534 if (SpvDimSubpassData != type.dimensions()) {
535 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
536 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700537 break;
538 }
539 default:
ethannicholasd598f792016-07-25 10:08:54 -0700540 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700541 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
542 } else {
543 ABORT("invalid type: %s", type.description().c_str());
544 }
545 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800546 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700547 return result;
548 }
549 return entry->second;
550}
551
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400552SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400553 SkASSERT(type.kind() == Type::kSampler_Kind);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400554 this->getType(type);
555 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400556 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400557 return fImageTypeMap[key];
558}
559
ethannicholasd598f792016-07-25 10:08:54 -0700560SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400561 String key = function.fReturnType.description() + "(";
562 String separator;
ethannicholasd598f792016-07-25 10:08:54 -0700563 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700564 key += separator;
565 separator = ", ";
ethannicholasd598f792016-07-25 10:08:54 -0700566 key += function.fParameters[i]->fType.description();
ethannicholasb3058bd2016-07-01 08:22:01 -0700567 }
568 key += ")";
569 auto entry = fTypeMap.find(key);
570 if (entry == fTypeMap.end()) {
571 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -0700572 int32_t length = 3 + (int32_t) function.fParameters.size();
573 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700574 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -0700575 for (size_t i = 0; i < function.fParameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500576 // glslang seems to treat all function arguments as pointers whether they need to be or
577 // not. I was initially puzzled by this until I ran bizarre failures with certain
578 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700579 // failure case:
580 //
581 // void sphere(float x) {
582 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500583 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700584 // void map() {
585 // sphere(1.0);
586 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500587 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700588 // void main() {
589 // for (int i = 0; i < 1; i++) {
590 // map();
591 // }
592 // }
593 //
Greg Daniel64773e62016-11-22 09:44:03 -0500594 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
595 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700596 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
597 // the spec makes this make sense.
598// if (is_out(function->fParameters[i])) {
ethannicholasd598f792016-07-25 10:08:54 -0700599 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -0700600 SpvStorageClassFunction));
601// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700602// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700603// }
604 }
605 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
606 this->writeWord(result, fConstantBuffer);
607 this->writeWord(returnType, fConstantBuffer);
608 for (SpvId id : parameterTypes) {
609 this->writeWord(id, fConstantBuffer);
610 }
611 fTypeMap[key] = result;
612 return result;
613 }
614 return entry->second;
615}
616
ethannicholas8ac838d2016-11-22 08:39:36 -0800617SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
618 return this->getPointerType(type, fDefaultLayout, storageClass);
619}
620
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400621SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700622 SpvStorageClass_ storageClass) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400623 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400624 String key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700625 auto entry = fTypeMap.find(key);
626 if (entry == fTypeMap.end()) {
627 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500628 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700629 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700630 fTypeMap[key] = result;
631 return result;
632 }
633 return entry->second;
634}
635
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400636SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700637 switch (expr.fKind) {
638 case Expression::kBinary_Kind:
639 return this->writeBinaryExpression((BinaryExpression&) expr, out);
640 case Expression::kBoolLiteral_Kind:
641 return this->writeBoolLiteral((BoolLiteral&) expr);
642 case Expression::kConstructor_Kind:
643 return this->writeConstructor((Constructor&) expr, out);
644 case Expression::kIntLiteral_Kind:
645 return this->writeIntLiteral((IntLiteral&) expr);
646 case Expression::kFieldAccess_Kind:
647 return this->writeFieldAccess(((FieldAccess&) expr), out);
648 case Expression::kFloatLiteral_Kind:
649 return this->writeFloatLiteral(((FloatLiteral&) expr));
650 case Expression::kFunctionCall_Kind:
651 return this->writeFunctionCall((FunctionCall&) expr, out);
652 case Expression::kPrefix_Kind:
653 return this->writePrefixExpression((PrefixExpression&) expr, out);
654 case Expression::kPostfix_Kind:
655 return this->writePostfixExpression((PostfixExpression&) expr, out);
656 case Expression::kSwizzle_Kind:
657 return this->writeSwizzle((Swizzle&) expr, out);
658 case Expression::kVariableReference_Kind:
659 return this->writeVariableReference((VariableReference&) expr, out);
660 case Expression::kTernary_Kind:
661 return this->writeTernaryExpression((TernaryExpression&) expr, out);
662 case Expression::kIndex_Kind:
663 return this->writeIndexExpression((IndexExpression&) expr, out);
664 default:
665 ABORT("unsupported expression: %s", expr.description().c_str());
666 }
667 return -1;
668}
669
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400670SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700671 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400672 SkASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -0700673 int32_t intrinsicId;
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400674 if (c.fArguments.size() > 0) {
675 const Type& type = c.fArguments[0]->fType;
676 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
677 intrinsicId = std::get<1>(intrinsic->second);
678 } else if (is_signed(fContext, type)) {
679 intrinsicId = std::get<2>(intrinsic->second);
680 } else if (is_unsigned(fContext, type)) {
681 intrinsicId = std::get<3>(intrinsic->second);
682 } else if (is_bool(fContext, type)) {
683 intrinsicId = std::get<4>(intrinsic->second);
684 } else {
685 intrinsicId = std::get<1>(intrinsic->second);
686 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700687 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400688 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700689 }
690 switch (std::get<0>(intrinsic->second)) {
691 case kGLSL_STD_450_IntrinsicKind: {
692 SpvId result = this->nextId();
693 std::vector<SpvId> arguments;
694 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400695 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
696 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
697 } else {
698 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
699 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700700 }
701 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700702 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700703 this->writeWord(result, out);
704 this->writeWord(fGLSLExtendedInstructions, out);
705 this->writeWord(intrinsicId, out);
706 for (SpvId id : arguments) {
707 this->writeWord(id, out);
708 }
709 return result;
710 }
711 case kSPIRV_IntrinsicKind: {
712 SpvId result = this->nextId();
713 std::vector<SpvId> arguments;
714 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400715 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
716 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
717 } else {
718 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
719 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700720 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400721 if (c.fType != *fContext.fVoid_Type) {
722 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
723 this->writeWord(this->getType(c.fType), out);
724 this->writeWord(result, out);
725 } else {
726 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
727 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700728 for (SpvId id : arguments) {
729 this->writeWord(id, out);
730 }
731 return result;
732 }
733 case kSpecial_IntrinsicKind:
734 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
735 default:
736 ABORT("unsupported intrinsic kind");
737 }
738}
739
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500740std::vector<SpvId> SPIRVCodeGenerator::vectorize(
741 const std::vector<std::unique_ptr<Expression>>& args,
742 OutputStream& out) {
743 int vectorSize = 0;
744 for (const auto& a : args) {
745 if (a->fType.kind() == Type::kVector_Kind) {
746 if (vectorSize) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400747 SkASSERT(a->fType.columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500748 }
749 else {
750 vectorSize = a->fType.columns();
751 }
752 }
753 }
754 std::vector<SpvId> result;
755 for (const auto& a : args) {
756 SpvId raw = this->writeExpression(*a, out);
757 if (vectorSize && a->fType.kind() == Type::kScalar_Kind) {
758 SpvId vector = this->nextId();
759 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
760 this->writeWord(this->getType(a->fType.toCompound(fContext, vectorSize, 1)), out);
761 this->writeWord(vector, out);
762 for (int i = 0; i < vectorSize; i++) {
763 this->writeWord(raw, out);
764 }
765 result.push_back(vector);
766 } else {
767 result.push_back(raw);
768 }
769 }
770 return result;
771}
772
773void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
774 SpvId signedInst, SpvId unsignedInst,
775 const std::vector<SpvId>& args,
776 OutputStream& out) {
777 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
778 this->writeWord(this->getType(type), out);
779 this->writeWord(id, out);
780 this->writeWord(fGLSLExtendedInstructions, out);
781
782 if (is_float(fContext, type)) {
783 this->writeWord(floatInst, out);
784 } else if (is_signed(fContext, type)) {
785 this->writeWord(signedInst, out);
786 } else if (is_unsigned(fContext, type)) {
787 this->writeWord(unsignedInst, out);
788 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400789 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500790 }
791 for (SpvId a : args) {
792 this->writeWord(a, out);
793 }
794}
795
Greg Daniel64773e62016-11-22 09:44:03 -0500796SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400797 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700798 SpvId result = this->nextId();
799 switch (kind) {
800 case kAtan_SpecialIntrinsic: {
801 std::vector<SpvId> arguments;
802 for (size_t i = 0; i < c.fArguments.size(); i++) {
803 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
804 }
805 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700806 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700807 this->writeWord(result, out);
808 this->writeWord(fGLSLExtendedInstructions, out);
809 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
810 for (SpvId id : arguments) {
811 this->writeWord(id, out);
812 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400813 break;
814 }
815 case kSubpassLoad_SpecialIntrinsic: {
816 SpvId img = this->writeExpression(*c.fArguments[0], out);
817 std::vector<std::unique_ptr<Expression>> args;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700818 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
819 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
820 Constructor ctor(-1, *fContext.fFloat2_Type, std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400821 SpvId coords = this->writeConstantVector(ctor);
822 if (1 == c.fArguments.size()) {
823 this->writeInstruction(SpvOpImageRead,
824 this->getType(c.fType),
825 result,
826 img,
827 coords,
828 out);
829 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400830 SkASSERT(2 == c.fArguments.size());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400831 SpvId sample = this->writeExpression(*c.fArguments[1], out);
832 this->writeInstruction(SpvOpImageRead,
833 this->getType(c.fType),
834 result,
835 img,
836 coords,
837 SpvImageOperandsSampleMask,
838 sample,
839 out);
840 }
841 break;
842 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700843 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500844 SpvOp_ op = SpvOpImageSampleImplicitLod;
845 switch (c.fArguments[0]->fType.dimensions()) {
846 case SpvDim1D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400847 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500848 op = SpvOpImageSampleProjImplicitLod;
849 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400850 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500851 }
852 break;
853 case SpvDim2D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400854 if (c.fArguments[1]->fType == *fContext.fFloat3_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.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500858 }
859 break;
860 case SpvDim3D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400861 if (c.fArguments[1]->fType == *fContext.fFloat4_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.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500865 }
866 break;
867 case SpvDimCube: // fall through
868 case SpvDimRect: // fall through
869 case SpvDimBuffer: // fall through
870 case SpvDimSubpassData:
871 break;
872 }
ethannicholasd598f792016-07-25 10:08:54 -0700873 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700874 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
875 SpvId uv = this->writeExpression(*c.fArguments[1], out);
876 if (c.fArguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500877 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700878 SpvImageOperandsBiasMask,
879 this->writeExpression(*c.fArguments[2], out),
880 out);
881 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400882 SkASSERT(c.fArguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500883 if (fProgram.fSettings.fSharpenTextures) {
884 FloatLiteral lodBias(fContext, -1, -0.5);
885 this->writeInstruction(op, type, result, sampler, uv,
886 SpvImageOperandsBiasMask,
887 this->writeFloatLiteral(lodBias),
888 out);
889 } else {
890 this->writeInstruction(op, type, result, sampler, uv,
891 out);
892 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700893 }
894 break;
895 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500896 case kMod_SpecialIntrinsic: {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500897 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400898 SkASSERT(args.size() == 2);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500899 const Type& operandType = c.fArguments[0]->fType;
900 SpvOp_ op;
901 if (is_float(fContext, operandType)) {
902 op = SpvOpFMod;
903 } else if (is_signed(fContext, operandType)) {
904 op = SpvOpSMod;
905 } else if (is_unsigned(fContext, operandType)) {
906 op = SpvOpUMod;
907 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400908 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500909 return 0;
910 }
911 this->writeOpCode(op, 5, out);
912 this->writeWord(this->getType(operandType), out);
913 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500914 this->writeWord(args[0], out);
915 this->writeWord(args[1], out);
916 break;
917 }
918 case kClamp_SpecialIntrinsic: {
919 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400920 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500921 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
922 GLSLstd450UClamp, args, out);
923 break;
924 }
925 case kMax_SpecialIntrinsic: {
926 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400927 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500928 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMax, GLSLstd450SMax,
929 GLSLstd450UMax, args, out);
930 break;
931 }
932 case kMin_SpecialIntrinsic: {
933 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400934 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500935 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMin, GLSLstd450SMin,
936 GLSLstd450UMin, args, out);
937 break;
938 }
939 case kMix_SpecialIntrinsic: {
940 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400941 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500942 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMix, SpvOpUndef,
943 SpvOpUndef, args, out);
944 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500945 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400946 case kSaturate_SpecialIntrinsic: {
947 SkASSERT(c.fArguments.size() == 1);
948 std::vector<std::unique_ptr<Expression>> finalArgs;
949 finalArgs.push_back(c.fArguments[0]->clone());
950 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 0));
951 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 1));
952 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
953 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
954 GLSLstd450UClamp, spvArgs, out);
955 break;
956 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700957 }
958 return result;
959}
960
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400961SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700962 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -0700963 if (entry == fFunctionMap.end()) {
964 return this->writeIntrinsicCall(c, out);
965 }
966 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
967 std::vector<std::tuple<SpvId, SpvId, std::unique_ptr<LValue>>> lvalues;
968 std::vector<SpvId> arguments;
969 for (size_t i = 0; i < c.fArguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500970 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -0700971 // passed directly
972 SpvId tmpVar;
973 // if we need a temporary var to store this argument, this is the value to store in the var
974 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -0700975 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700976 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
977 SpvId ptr = lv->getPointer();
978 if (ptr) {
979 arguments.push_back(ptr);
980 continue;
981 } else {
982 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
983 // copy it into a temp, call the function, read the value out of the temp, and then
984 // update the lvalue.
985 tmpValueId = lv->load(out);
986 tmpVar = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -0700987 lvalues.push_back(std::make_tuple(tmpVar, this->getType(c.fArguments[i]->fType),
ethannicholasb3058bd2016-07-01 08:22:01 -0700988 std::move(lv)));
989 }
990 } else {
991 // see getFunctionType for an explanation of why we're always using pointer parameters
992 tmpValueId = this->writeExpression(*c.fArguments[i], out);
993 tmpVar = this->nextId();
994 }
Greg Daniel64773e62016-11-22 09:44:03 -0500995 this->writeInstruction(SpvOpVariable,
996 this->getPointerType(c.fArguments[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -0700997 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -0500998 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -0700999 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001000 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001001 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1002 arguments.push_back(tmpVar);
1003 }
1004 SpvId result = this->nextId();
1005 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001006 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001007 this->writeWord(result, out);
1008 this->writeWord(entry->second, out);
1009 for (SpvId id : arguments) {
1010 this->writeWord(id, out);
1011 }
1012 // now that the call is complete, we may need to update some lvalues with the new values of out
1013 // arguments
1014 for (const auto& tuple : lvalues) {
1015 SpvId load = this->nextId();
1016 this->writeInstruction(SpvOpLoad, std::get<1>(tuple), load, std::get<0>(tuple), out);
1017 std::get<2>(tuple)->store(load, out);
1018 }
1019 return result;
1020}
1021
ethannicholasf789b382016-08-03 12:43:36 -07001022SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001023 SkASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001024 SpvId result = this->nextId();
1025 std::vector<SpvId> arguments;
1026 for (size_t i = 0; i < c.fArguments.size(); i++) {
1027 arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1028 }
ethannicholasd598f792016-07-25 10:08:54 -07001029 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001030 if (c.fArguments.size() == 1) {
1031 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001032 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001033 this->writeWord(type, fConstantBuffer);
1034 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001035 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001036 this->writeWord(arguments[0], fConstantBuffer);
1037 }
1038 } else {
Greg Daniel64773e62016-11-22 09:44:03 -05001039 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001040 fConstantBuffer);
1041 this->writeWord(type, fConstantBuffer);
1042 this->writeWord(result, fConstantBuffer);
1043 for (SpvId id : arguments) {
1044 this->writeWord(id, fConstantBuffer);
1045 }
1046 }
1047 return result;
1048}
1049
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001050SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001051 SkASSERT(c.fType.isFloat());
1052 SkASSERT(c.fArguments.size() == 1);
1053 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001054 SpvId result = this->nextId();
1055 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001056 if (c.fArguments[0]->fType.isSigned()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001057 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001058 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001059 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001060 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Greg Daniel64773e62016-11-22 09:44:03 -05001061 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001062 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001063 }
1064 return result;
1065}
1066
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001067SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001068 SkASSERT(c.fType.isSigned());
1069 SkASSERT(c.fArguments.size() == 1);
1070 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001071 SpvId result = this->nextId();
1072 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001073 if (c.fArguments[0]->fType.isFloat()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001074 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001075 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001076 }
1077 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001078 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001079 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001080 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001081 }
1082 return result;
1083}
1084
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001085SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001086 SkASSERT(c.fType.isUnsigned());
1087 SkASSERT(c.fArguments.size() == 1);
1088 SkASSERT(c.fArguments[0]->fType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001089 SpvId result = this->nextId();
1090 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001091 if (c.fArguments[0]->fType.isFloat()) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001092 this->writeInstruction(SpvOpConvertFToU, this->getType(c.fType), result, parameter,
1093 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001094 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001095 SkASSERT(c.fArguments[0]->fType.isSigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001096 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
1097 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001098 }
1099 return result;
1100}
1101
Ethan Nicholas84645e32017-02-09 13:57:14 -05001102void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001103 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001104 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001105 SpvId zeroId = this->writeFloatLiteral(zero);
1106 std::vector<SpvId> columnIds;
1107 for (int column = 0; column < type.columns(); column++) {
1108 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1109 out);
1110 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1111 out);
1112 SpvId columnId = this->nextId();
1113 this->writeWord(columnId, out);
1114 columnIds.push_back(columnId);
1115 for (int row = 0; row < type.columns(); row++) {
1116 this->writeWord(row == column ? diagonal : zeroId, out);
1117 }
1118 }
1119 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1120 out);
1121 this->writeWord(this->getType(type), out);
1122 this->writeWord(id, out);
1123 for (SpvId id : columnIds) {
1124 this->writeWord(id, out);
1125 }
1126}
1127
1128void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001129 const Type& dstType, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001130 SkASSERT(srcType.kind() == Type::kMatrix_Kind);
1131 SkASSERT(dstType.kind() == Type::kMatrix_Kind);
1132 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001133 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1134 srcType.rows(),
1135 1));
1136 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1137 dstType.rows(),
1138 1));
1139 SpvId zeroId;
1140 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001141 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001142 zeroId = this->writeFloatLiteral(zero);
1143 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001144 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001145 zeroId = this->writeIntLiteral(zero);
1146 } else {
1147 ABORT("unsupported matrix component type");
1148 }
1149 SpvId zeroColumn = 0;
1150 SpvId columns[4];
1151 for (int i = 0; i < dstType.columns(); i++) {
1152 if (i < srcType.columns()) {
1153 // we're still inside the src matrix, copy the column
1154 SpvId srcColumn = this->nextId();
1155 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
1156 SpvId dstColumn;
1157 if (srcType.rows() == dstType.rows()) {
1158 // columns are equal size, don't need to do anything
1159 dstColumn = srcColumn;
1160 }
1161 else if (dstType.rows() > srcType.rows()) {
1162 // dst column is bigger, need to zero-pad it
1163 dstColumn = this->nextId();
1164 int delta = dstType.rows() - srcType.rows();
1165 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1166 this->writeWord(dstColumnType, out);
1167 this->writeWord(dstColumn, out);
1168 this->writeWord(srcColumn, out);
1169 for (int i = 0; i < delta; ++i) {
1170 this->writeWord(zeroId, out);
1171 }
1172 }
1173 else {
1174 // dst column is smaller, need to swizzle the src column
1175 dstColumn = this->nextId();
1176 int count = dstType.rows();
1177 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1178 this->writeWord(dstColumnType, out);
1179 this->writeWord(dstColumn, out);
1180 this->writeWord(srcColumn, out);
1181 this->writeWord(srcColumn, out);
1182 for (int i = 0; i < count; i++) {
1183 this->writeWord(i, out);
1184 }
1185 }
1186 columns[i] = dstColumn;
1187 } else {
1188 // we're past the end of the src matrix, need a vector of zeroes
1189 if (!zeroColumn) {
1190 zeroColumn = this->nextId();
1191 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1192 this->writeWord(dstColumnType, out);
1193 this->writeWord(zeroColumn, out);
1194 for (int i = 0; i < dstType.rows(); ++i) {
1195 this->writeWord(zeroId, out);
1196 }
1197 }
1198 columns[i] = zeroColumn;
1199 }
1200 }
1201 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1202 this->writeWord(this->getType(dstType), out);
1203 this->writeWord(id, out);
1204 for (int i = 0; i < dstType.columns(); i++) {
1205 this->writeWord(columns[i], out);
1206 }
Ethan Nicholas84645e32017-02-09 13:57:14 -05001207}
1208
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001209SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001210 SkASSERT(c.fType.kind() == Type::kMatrix_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001211 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1212 // an instruction
1213 std::vector<SpvId> arguments;
1214 for (size_t i = 0; i < c.fArguments.size(); i++) {
1215 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1216 }
1217 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001218 int rows = c.fType.rows();
1219 int columns = c.fType.columns();
Ethan Nicholas84645e32017-02-09 13:57:14 -05001220 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1221 this->writeUniformScaleMatrix(result, arguments[0], c.fType, out);
1222 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kMatrix_Kind) {
1223 this->writeMatrixCopy(result, arguments[0], c.fArguments[0]->fType, c.fType, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001224 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kVector_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001225 SkASSERT(c.fType.rows() == 2 && c.fType.columns() == 2);
1226 SkASSERT(c.fArguments[0]->fType.columns() == 4);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001227 SpvId componentType = this->getType(c.fType.componentType());
1228 SpvId v[4];
1229 for (int i = 0; i < 4; ++i) {
1230 v[i] = this->nextId();
1231 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i, out);
1232 }
1233 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, 2, 1));
1234 SpvId column1 = this->nextId();
1235 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1236 SpvId column2 = this->nextId();
1237 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
1238 this->writeInstruction(SpvOpCompositeConstruct, this->getType(c.fType), result, column1,
1239 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001240 } else {
1241 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001242 // ids of vectors and scalars we have written to the current column so far
1243 std::vector<SpvId> currentColumn;
1244 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001245 int currentCount = 0;
1246 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001247 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind &&
1248 c.fArguments[i]->fType.columns() == c.fType.rows()) {
1249 // this is a complete column by itself
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001250 SkASSERT(currentCount == 0);
ethannicholasb3058bd2016-07-01 08:22:01 -07001251 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001252 } else {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001253 if (c.fArguments[i]->fType.columns() == 1) {
1254 currentColumn.push_back(arguments[i]);
1255 } else {
1256 SpvId componentType = this->getType(c.fArguments[i]->fType.componentType());
Ethan Nicholas811b9442018-05-11 13:16:03 -04001257 for (int j = 0; j < c.fArguments[i]->fType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001258 SpvId swizzle = this->nextId();
1259 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1260 arguments[i], j, out);
1261 currentColumn.push_back(swizzle);
1262 }
1263 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001264 currentCount += c.fArguments[i]->fType.columns();
1265 if (currentCount == rows) {
1266 currentCount = 0;
1267 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn.size(), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001268 this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows,
1269 1)),
ethannicholasb3058bd2016-07-01 08:22:01 -07001270 out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001271 SpvId columnId = this->nextId();
1272 this->writeWord(columnId, out);
1273 columnIds.push_back(columnId);
1274 for (SpvId id : currentColumn) {
1275 this->writeWord(id, out);
1276 }
1277 currentColumn.clear();
ethannicholasb3058bd2016-07-01 08:22:01 -07001278 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001279 SkASSERT(currentCount < rows);
ethannicholasb3058bd2016-07-01 08:22:01 -07001280 }
1281 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001282 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001283 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001284 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001285 this->writeWord(result, out);
1286 for (SpvId id : columnIds) {
1287 this->writeWord(id, out);
1288 }
1289 }
1290 return result;
1291}
1292
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001293SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001294 SkASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001295 if (c.isConstant()) {
1296 return this->writeConstantVector(c);
1297 }
1298 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1299 // an instruction
1300 std::vector<SpvId> arguments;
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001301 for (size_t i = 0; i < c.fArguments.size(); i++) {
1302 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
1303 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1304 // extract the components and convert them in that case manually. On top of that,
1305 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1306 // doesn't handle vector arguments at all, so we always extract vector components and
1307 // pass them into OpCreateComposite individually.
1308 SpvId vec = this->writeExpression(*c.fArguments[i], out);
1309 SpvOp_ op = SpvOpUndef;
1310 const Type& src = c.fArguments[i]->fType.componentType();
1311 const Type& dst = c.fType.componentType();
1312 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1313 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1314 if (c.fArguments.size() == 1) {
1315 return vec;
1316 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001317 } else if (src == *fContext.fInt_Type ||
1318 src == *fContext.fShort_Type ||
1319 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001320 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001321 } else if (src == *fContext.fUInt_Type ||
1322 src == *fContext.fUShort_Type ||
1323 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001324 op = SpvOpConvertUToF;
1325 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001326 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001327 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001328 } else if (dst == *fContext.fInt_Type ||
1329 dst == *fContext.fShort_Type ||
1330 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001331 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1332 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001333 } else if (src == *fContext.fInt_Type ||
1334 src == *fContext.fShort_Type ||
1335 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001336 if (c.fArguments.size() == 1) {
1337 return vec;
1338 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001339 } else if (src == *fContext.fUInt_Type ||
1340 src == *fContext.fUShort_Type ||
1341 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001342 op = SpvOpBitcast;
1343 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001344 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001345 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001346 } else if (dst == *fContext.fUInt_Type ||
1347 dst == *fContext.fUShort_Type ||
1348 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001349 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1350 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001351 } else if (src == *fContext.fInt_Type ||
1352 src == *fContext.fShort_Type ||
1353 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001354 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001355 } else if (src == *fContext.fUInt_Type ||
1356 src == *fContext.fUShort_Type ||
1357 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001358 if (c.fArguments.size() == 1) {
1359 return vec;
1360 }
1361 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001362 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001363 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001364 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001365 for (int j = 0; j < c.fArguments[i]->fType.columns(); j++) {
1366 SpvId swizzle = this->nextId();
1367 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1368 out);
1369 if (op != SpvOpUndef) {
1370 SpvId cast = this->nextId();
1371 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1372 arguments.push_back(cast);
1373 } else {
1374 arguments.push_back(swizzle);
1375 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001376 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001377 } else {
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001378 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1379 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001380 }
1381 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001382 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1383 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1384 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001385 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001386 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001387 this->writeWord(arguments[0], out);
1388 }
1389 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001390 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001391 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001392 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001393 this->writeWord(result, out);
1394 for (SpvId id : arguments) {
1395 this->writeWord(id, out);
1396 }
1397 }
1398 return result;
1399}
1400
Ethan Nicholasbd553222017-07-18 15:54:59 -04001401SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001402 SkASSERT(c.fType.kind() == Type::kArray_Kind);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001403 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1404 // an instruction
1405 std::vector<SpvId> arguments;
1406 for (size_t i = 0; i < c.fArguments.size(); i++) {
1407 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1408 }
1409 SpvId result = this->nextId();
1410 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
1411 this->writeWord(this->getType(c.fType), out);
1412 this->writeWord(result, out);
1413 for (SpvId id : arguments) {
1414 this->writeWord(id, out);
1415 }
1416 return result;
1417}
1418
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001419SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001420 if (c.fArguments.size() == 1 &&
1421 this->getActualType(c.fType) == this->getActualType(c.fArguments[0]->fType)) {
1422 return this->writeExpression(*c.fArguments[0], out);
1423 }
1424 if (c.fType == *fContext.fFloat_Type || c.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001425 return this->writeFloatConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001426 } else if (c.fType == *fContext.fInt_Type ||
1427 c.fType == *fContext.fShort_Type ||
1428 c.fType == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001429 return this->writeIntConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001430 } else if (c.fType == *fContext.fUInt_Type ||
1431 c.fType == *fContext.fUShort_Type ||
1432 c.fType == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001433 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001434 }
ethannicholasd598f792016-07-25 10:08:54 -07001435 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001436 case Type::kVector_Kind:
1437 return this->writeVectorConstructor(c, out);
1438 case Type::kMatrix_Kind:
1439 return this->writeMatrixConstructor(c, out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001440 case Type::kArray_Kind:
1441 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001442 default:
1443 ABORT("unsupported constructor: %s", c.description().c_str());
1444 }
1445}
1446
1447SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1448 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001449 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001450 return SpvStorageClassInput;
1451 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001452 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001453 return SpvStorageClassOutput;
1454 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001455 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001456 return SpvStorageClassPushConstant;
1457 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001458 return SpvStorageClassUniform;
1459 } else {
1460 return SpvStorageClassFunction;
1461 }
1462}
1463
ethannicholasf789b382016-08-03 12:43:36 -07001464SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001465 switch (expr.fKind) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001466 case Expression::kVariableReference_Kind: {
1467 const Variable& var = ((VariableReference&) expr).fVariable;
1468 if (var.fStorage != Variable::kGlobal_Storage) {
1469 return SpvStorageClassFunction;
1470 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001471 SpvStorageClass_ result = get_storage_class(var.fModifiers);
1472 if (result == SpvStorageClassFunction) {
1473 result = SpvStorageClassPrivate;
1474 }
1475 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001476 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001477 case Expression::kFieldAccess_Kind:
1478 return get_storage_class(*((FieldAccess&) expr).fBase);
1479 case Expression::kIndex_Kind:
1480 return get_storage_class(*((IndexExpression&) expr).fBase);
1481 default:
1482 return SpvStorageClassFunction;
1483 }
1484}
1485
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001486std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001487 std::vector<SpvId> chain;
1488 switch (expr.fKind) {
1489 case Expression::kIndex_Kind: {
1490 IndexExpression& indexExpr = (IndexExpression&) expr;
1491 chain = this->getAccessChain(*indexExpr.fBase, out);
1492 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1493 break;
1494 }
1495 case Expression::kFieldAccess_Kind: {
1496 FieldAccess& fieldExpr = (FieldAccess&) expr;
1497 chain = this->getAccessChain(*fieldExpr.fBase, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001498 IntLiteral index(fContext, -1, fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001499 chain.push_back(this->writeIntLiteral(index));
1500 break;
1501 }
1502 default:
1503 chain.push_back(this->getLValue(expr, out)->getPointer());
1504 }
1505 return chain;
1506}
1507
1508class PointerLValue : public SPIRVCodeGenerator::LValue {
1509public:
Greg Daniel64773e62016-11-22 09:44:03 -05001510 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type)
ethannicholasb3058bd2016-07-01 08:22:01 -07001511 : fGen(gen)
1512 , fPointer(pointer)
1513 , fType(type) {}
1514
1515 virtual SpvId getPointer() override {
1516 return fPointer;
1517 }
1518
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001519 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001520 SpvId result = fGen.nextId();
1521 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
1522 return result;
1523 }
1524
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001525 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001526 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1527 }
1528
1529private:
1530 SPIRVCodeGenerator& fGen;
1531 const SpvId fPointer;
1532 const SpvId fType;
1533};
1534
1535class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1536public:
Greg Daniel64773e62016-11-22 09:44:03 -05001537 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
ethannicholasb3058bd2016-07-01 08:22:01 -07001538 const Type& baseType, const Type& swizzleType)
1539 : fGen(gen)
1540 , fVecPointer(vecPointer)
1541 , fComponents(components)
1542 , fBaseType(baseType)
1543 , fSwizzleType(swizzleType) {}
1544
1545 virtual SpvId getPointer() override {
1546 return 0;
1547 }
1548
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001549 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001550 SpvId base = fGen.nextId();
1551 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1552 SpvId result = fGen.nextId();
1553 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1554 fGen.writeWord(fGen.getType(fSwizzleType), out);
1555 fGen.writeWord(result, out);
1556 fGen.writeWord(base, out);
1557 fGen.writeWord(base, out);
1558 for (int component : fComponents) {
1559 fGen.writeWord(component, out);
1560 }
1561 return result;
1562 }
1563
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001564 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001565 // use OpVectorShuffle to mix and match the vector components. We effectively create
1566 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001567 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001568 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001569 // float3L = ...;
1570 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001571 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001572 // 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 -07001573 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1574 // (3, 1, 4).
1575 SpvId base = fGen.nextId();
1576 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1577 SpvId shuffle = fGen.nextId();
1578 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1579 fGen.writeWord(fGen.getType(fBaseType), out);
1580 fGen.writeWord(shuffle, out);
1581 fGen.writeWord(base, out);
1582 fGen.writeWord(value, out);
1583 for (int i = 0; i < fBaseType.columns(); i++) {
1584 // current offset into the virtual vector, defaults to pulling the unmodified
1585 // value from the left side
1586 int offset = i;
1587 // check to see if we are writing this component
1588 for (size_t j = 0; j < fComponents.size(); j++) {
1589 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001590 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001591 // the correct component of the right side instead of preserving the
1592 // value from the left
1593 offset = (int) (j + fBaseType.columns());
1594 break;
1595 }
1596 }
1597 fGen.writeWord(offset, out);
1598 }
1599 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1600 }
1601
1602private:
1603 SPIRVCodeGenerator& fGen;
1604 const SpvId fVecPointer;
1605 const std::vector<int>& fComponents;
1606 const Type& fBaseType;
1607 const Type& fSwizzleType;
1608};
1609
Greg Daniel64773e62016-11-22 09:44:03 -05001610std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001611 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001612 switch (expr.fKind) {
1613 case Expression::kVariableReference_Kind: {
Ethan Nicholas5226b772018-05-03 16:20:41 -04001614 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07001615 const Variable& var = ((VariableReference&) expr).fVariable;
Ethan Nicholas5226b772018-05-03 16:20:41 -04001616 if (var.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
1617 type = this->getType(Type("sk_in", Type::kArray_Kind, var.fType.componentType(),
1618 fSkInCount));
1619 } else {
1620 type = this->getType(expr.fType);
1621 }
ethannicholasd598f792016-07-25 10:08:54 -07001622 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001623 SkASSERT(entry != fVariableMap.end());
Ethan Nicholas5226b772018-05-03 16:20:41 -04001624 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(*this,
1625 entry->second,
1626 type));
ethannicholasb3058bd2016-07-01 08:22:01 -07001627 }
1628 case Expression::kIndex_Kind: // fall through
1629 case Expression::kFieldAccess_Kind: {
1630 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1631 SpvId member = this->nextId();
1632 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001633 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001634 this->writeWord(member, out);
1635 for (SpvId idx : chain) {
1636 this->writeWord(idx, out);
1637 }
1638 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -04001639 *this,
1640 member,
1641 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001642 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001643 case Expression::kSwizzle_Kind: {
1644 Swizzle& swizzle = (Swizzle&) expr;
1645 size_t count = swizzle.fComponents.size();
1646 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001647 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001648 if (count == 1) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001649 IntLiteral index(fContext, -1, swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001650 SpvId member = this->nextId();
1651 this->writeInstruction(SpvOpAccessChain,
Greg Daniel64773e62016-11-22 09:44:03 -05001652 this->getPointerType(swizzle.fType,
1653 get_storage_class(*swizzle.fBase)),
1654 member,
1655 base,
1656 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001657 out);
1658 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1659 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001660 member,
ethannicholasd598f792016-07-25 10:08:54 -07001661 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001662 } else {
1663 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
Greg Daniel64773e62016-11-22 09:44:03 -05001664 *this,
1665 base,
1666 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001667 swizzle.fBase->fType,
1668 expr.fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07001669 }
1670 }
Ethan Nicholasa583b812018-01-18 13:32:11 -05001671 case Expression::kTernary_Kind: {
1672 TernaryExpression& t = (TernaryExpression&) expr;
1673 SpvId test = this->writeExpression(*t.fTest, out);
1674 SpvId end = this->nextId();
1675 SpvId ifTrueLabel = this->nextId();
1676 SpvId ifFalseLabel = this->nextId();
1677 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1678 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1679 this->writeLabel(ifTrueLabel, out);
1680 SpvId ifTrue = this->getLValue(*t.fIfTrue, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001681 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001682 this->writeInstruction(SpvOpBranch, end, out);
1683 ifTrueLabel = fCurrentBlock;
1684 SpvId ifFalse = this->getLValue(*t.fIfFalse, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001685 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001686 ifFalseLabel = fCurrentBlock;
1687 this->writeInstruction(SpvOpBranch, end, out);
1688 SpvId result = this->nextId();
1689 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1690 ifTrueLabel, ifFalse, ifFalseLabel, out);
1691 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1692 *this,
1693 result,
1694 this->getType(expr.fType)));
1695 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001696 default:
1697 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001698 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001699 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1700 // caught by IRGenerator
1701 SpvId result = this->nextId();
1702 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001703 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1704 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001705 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1706 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1707 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001708 result,
ethannicholasd598f792016-07-25 10:08:54 -07001709 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001710 }
1711}
1712
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001713SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001714 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001715 auto entry = fVariableMap.find(&ref.fVariable);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001716 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001717 SpvId var = entry->second;
ethannicholasd598f792016-07-25 10:08:54 -07001718 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001719 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
1720 fProgram.fSettings.fFlipY) {
1721 // need to remap to a top-left coordinate system
Greg Daniele6ab9982018-08-22 13:56:32 +00001722 if (fRTHeightStructId == (SpvId) -1) {
1723 // height variable hasn't been written yet
1724 std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors));
1725 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
1726 std::vector<Type::Field> fields;
1727 fields.emplace_back(Modifiers(), SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1728 StringFragment name("sksl_synthetic_uniforms");
1729 Type intfStruct(-1, name, fields);
1730 Layout layout(0, -1, -1, 1, -1, -1, -1, -1, Layout::Format::kUnspecified,
1731 Layout::kUnspecified_Primitive, -1, -1, "", Layout::kNo_Key,
Ethan Nicholas78aceb22018-08-31 16:13:58 -04001732 Layout::CType::kDefault);
Greg Daniele6ab9982018-08-22 13:56:32 +00001733 Variable* intfVar = new Variable(-1,
1734 Modifiers(layout, Modifiers::kUniform_Flag),
1735 name,
1736 intfStruct,
1737 Variable::kGlobal_Storage);
1738 fSynthetics.takeOwnership(intfVar);
1739 InterfaceBlock intf(-1, intfVar, name, String(""),
1740 std::vector<std::unique_ptr<Expression>>(), st);
1741 fRTHeightStructId = this->writeInterfaceBlock(intf);
1742 fRTHeightFieldIndex = 0;
1743 }
1744 SkASSERT(fRTHeightFieldIndex != (SpvId) -1);
1745 // write float4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, 1.0)
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001746 SpvId xId = this->nextId();
1747 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1748 result, 0, out);
Greg Daniele6ab9982018-08-22 13:56:32 +00001749 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1750 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1751 SpvId heightPtr = this->nextId();
1752 this->writeOpCode(SpvOpAccessChain, 5, out);
1753 this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out);
1754 this->writeWord(heightPtr, out);
1755 this->writeWord(fRTHeightStructId, out);
1756 this->writeWord(fieldIndexId, out);
1757 SpvId heightRead = this->nextId();
1758 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1759 heightPtr, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001760 SpvId rawYId = this->nextId();
1761 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1762 result, 1, out);
1763 SpvId flippedYId = this->nextId();
1764 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
Greg Daniele6ab9982018-08-22 13:56:32 +00001765 heightRead, rawYId, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001766 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001767 SpvId zeroId = writeFloatLiteral(zero);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001768 FloatLiteral one(fContext, -1, 1.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001769 SpvId oneId = writeFloatLiteral(one);
1770 SpvId flipped = this->nextId();
1771 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001772 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001773 this->writeWord(flipped, out);
1774 this->writeWord(xId, out);
1775 this->writeWord(flippedYId, out);
1776 this->writeWord(zeroId, out);
1777 this->writeWord(oneId, out);
1778 return flipped;
1779 }
Chris Daltonb91c4662018-08-01 10:46:22 -06001780 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
1781 !fProgram.fSettings.fFlipY) {
1782 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1783 // the default convention of "counter-clockwise face is front".
1784 SpvId inverse = this->nextId();
1785 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1786 result, out);
1787 return inverse;
1788 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001789 return result;
1790}
1791
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001792SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001793 return getLValue(expr, out)->load(out);
1794}
1795
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001796SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001797 return getLValue(f, out)->load(out);
1798}
1799
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001800SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001801 SpvId base = this->writeExpression(*swizzle.fBase, out);
1802 SpvId result = this->nextId();
1803 size_t count = swizzle.fComponents.size();
1804 if (count == 1) {
Greg Daniel64773e62016-11-22 09:44:03 -05001805 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
1806 swizzle.fComponents[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001807 } else {
1808 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
ethannicholasd598f792016-07-25 10:08:54 -07001809 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001810 this->writeWord(result, out);
1811 this->writeWord(base, out);
1812 this->writeWord(base, out);
1813 for (int component : swizzle.fComponents) {
1814 this->writeWord(component, out);
1815 }
1816 }
1817 return result;
1818}
1819
Greg Daniel64773e62016-11-22 09:44:03 -05001820SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1821 const Type& operandType, SpvId lhs,
1822 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001823 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001824 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001825 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001826 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001827 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001828 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001829 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001830 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001831 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001832 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
1833 } else {
1834 ABORT("invalid operandType: %s", operandType.description().c_str());
1835 }
1836 return result;
1837}
1838
1839bool is_assignment(Token::Kind op) {
1840 switch (op) {
1841 case Token::EQ: // fall through
1842 case Token::PLUSEQ: // fall through
1843 case Token::MINUSEQ: // fall through
1844 case Token::STAREQ: // fall through
1845 case Token::SLASHEQ: // fall through
1846 case Token::PERCENTEQ: // fall through
1847 case Token::SHLEQ: // fall through
1848 case Token::SHREQ: // fall through
1849 case Token::BITWISEOREQ: // fall through
1850 case Token::BITWISEXOREQ: // fall through
1851 case Token::BITWISEANDEQ: // fall through
1852 case Token::LOGICALOREQ: // fall through
1853 case Token::LOGICALXOREQ: // fall through
1854 case Token::LOGICALANDEQ:
1855 return true;
1856 default:
1857 return false;
1858 }
1859}
1860
Ethan Nicholas48e24052018-03-14 13:51:39 -04001861SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
1862 OutputStream& out) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05001863 if (operandType.kind() == Type::kVector_Kind) {
1864 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001865 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05001866 return result;
1867 }
1868 return id;
1869}
1870
Ethan Nicholas68990be2017-07-13 09:36:52 -04001871SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
1872 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04001873 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04001874 OutputStream& out) {
1875 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001876 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0df21132018-07-10 09:37:51 -04001877 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
1878 operandType.rows(),
1879 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04001880 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04001881 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04001882 1));
1883 SpvId boolType = this->getType(*fContext.fBool_Type);
1884 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04001885 for (int i = 0; i < operandType.columns(); i++) {
1886 SpvId columnL = this->nextId();
1887 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
1888 SpvId columnR = this->nextId();
1889 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04001890 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04001891 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
1892 SpvId merge = this->nextId();
1893 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04001894 if (result != 0) {
1895 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04001896 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04001897 result = next;
1898 }
1899 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04001900 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04001901 }
1902 }
1903 return result;
1904}
1905
Ethan Nicholas0df21132018-07-10 09:37:51 -04001906SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
1907 SpvId rhs, SpvOp_ floatOperator,
1908 SpvOp_ intOperator,
1909 OutputStream& out) {
1910 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
1911 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
1912 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
1913 operandType.rows(),
1914 1));
1915 SpvId columns[4];
1916 for (int i = 0; i < operandType.columns(); i++) {
1917 SpvId columnL = this->nextId();
1918 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
1919 SpvId columnR = this->nextId();
1920 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
1921 columns[i] = this->nextId();
1922 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
1923 }
1924 SpvId result = this->nextId();
1925 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
1926 this->writeWord(this->getType(operandType), out);
1927 this->writeWord(result, out);
1928 for (int i = 0; i < operandType.columns(); i++) {
1929 this->writeWord(columns[i], out);
1930 }
1931 return result;
1932}
1933
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001934SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001935 // handle cases where we don't necessarily evaluate both LHS and RHS
1936 switch (b.fOperator) {
1937 case Token::EQ: {
1938 SpvId rhs = this->writeExpression(*b.fRight, out);
1939 this->getLValue(*b.fLeft, out)->store(rhs, out);
1940 return rhs;
1941 }
1942 case Token::LOGICALAND:
1943 return this->writeLogicalAnd(b, out);
1944 case Token::LOGICALOR:
1945 return this->writeLogicalOr(b, out);
1946 default:
1947 break;
1948 }
1949
1950 // "normal" operators
ethannicholasd598f792016-07-25 10:08:54 -07001951 const Type& resultType = b.fType;
ethannicholasb3058bd2016-07-01 08:22:01 -07001952 std::unique_ptr<LValue> lvalue;
1953 SpvId lhs;
1954 if (is_assignment(b.fOperator)) {
1955 lvalue = this->getLValue(*b.fLeft, out);
1956 lhs = lvalue->load(out);
1957 } else {
1958 lvalue = nullptr;
1959 lhs = this->writeExpression(*b.fLeft, out);
1960 }
1961 SpvId rhs = this->writeExpression(*b.fRight, out);
Ethan Nicholas6feb6912017-06-30 12:23:36 -04001962 if (b.fOperator == Token::COMMA) {
1963 return rhs;
1964 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001965 Type tmp("<invalid>");
Ethan Nicholas48e24052018-03-14 13:51:39 -04001966 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07001967 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04001968 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
1969 // handling in SPIR-V
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001970 if (this->getActualType(b.fLeft->fType) != this->getActualType(b.fRight->fType)) {
Greg Daniel64773e62016-11-22 09:44:03 -05001971 if (b.fLeft->fType.kind() == Type::kVector_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07001972 b.fRight->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001973 // promote number to vector
1974 SpvId vec = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001975 const Type& vecType = b.fLeft->fType;
1976 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
1977 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001978 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04001979 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001980 this->writeWord(rhs, out);
1981 }
1982 rhs = vec;
Ethan Nicholas48e24052018-03-14 13:51:39 -04001983 operandType = &b.fLeft->fType;
Greg Daniel64773e62016-11-22 09:44:03 -05001984 } else if (b.fRight->fType.kind() == Type::kVector_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07001985 b.fLeft->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001986 // promote number to vector
1987 SpvId vec = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001988 const Type& vecType = b.fRight->fType;
1989 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
1990 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001991 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04001992 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001993 this->writeWord(lhs, out);
1994 }
1995 lhs = vec;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001996 SkASSERT(!lvalue);
Ethan Nicholas48e24052018-03-14 13:51:39 -04001997 operandType = &b.fRight->fType;
ethannicholasd598f792016-07-25 10:08:54 -07001998 } else if (b.fLeft->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001999 SpvOp_ op;
ethannicholasd598f792016-07-25 10:08:54 -07002000 if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002001 op = SpvOpMatrixTimesMatrix;
ethannicholasd598f792016-07-25 10:08:54 -07002002 } else if (b.fRight->fType.kind() == Type::kVector_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002003 op = SpvOpMatrixTimesVector;
2004 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002005 SkASSERT(b.fRight->fType.kind() == Type::kScalar_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07002006 op = SpvOpMatrixTimesScalar;
2007 }
2008 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002009 this->writeInstruction(op, this->getType(b.fType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002010 if (b.fOperator == Token::STAREQ) {
2011 lvalue->store(result, out);
2012 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002013 SkASSERT(b.fOperator == Token::STAR);
ethannicholasb3058bd2016-07-01 08:22:01 -07002014 }
2015 return result;
ethannicholasd598f792016-07-25 10:08:54 -07002016 } else if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002017 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002018 if (b.fLeft->fType.kind() == Type::kVector_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05002019 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(b.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002020 lhs, rhs, out);
2021 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002022 SkASSERT(b.fLeft->fType.kind() == Type::kScalar_Kind);
Greg Daniel64773e62016-11-22 09:44:03 -05002023 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(b.fType), result, rhs,
ethannicholasb3058bd2016-07-01 08:22:01 -07002024 lhs, out);
2025 }
2026 if (b.fOperator == Token::STAREQ) {
2027 lvalue->store(result, out);
2028 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002029 SkASSERT(b.fOperator == Token::STAR);
ethannicholasb3058bd2016-07-01 08:22:01 -07002030 }
2031 return result;
2032 } else {
2033 ABORT("unsupported binary expression: %s", b.description().c_str());
2034 }
2035 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002036 tmp = this->getActualType(b.fLeft->fType);
2037 operandType = &tmp;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002038 SkASSERT(*operandType == this->getActualType(b.fRight->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002039 }
2040 switch (b.fOperator) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002041 case Token::EQEQ: {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002042 if (operandType->kind() == Type::kMatrix_Kind) {
2043 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002044 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002045 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002046 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002047 const Type* tmpType;
2048 if (operandType->kind() == Type::kVector_Kind) {
2049 tmpType = &fContext.fBool_Type->toCompound(fContext,
2050 operandType->columns(),
2051 operandType->rows());
2052 } else {
2053 tmpType = &resultType;
2054 }
2055 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002056 SpvOpFOrdEqual, SpvOpIEqual,
2057 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002058 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002059 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002060 case Token::NEQ:
Ethan Nicholas68990be2017-07-13 09:36:52 -04002061 if (operandType->kind() == Type::kMatrix_Kind) {
2062 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002063 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002064 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002065 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002066 const Type* tmpType;
2067 if (operandType->kind() == Type::kVector_Kind) {
2068 tmpType = &fContext.fBool_Type->toCompound(fContext,
2069 operandType->columns(),
2070 operandType->rows());
2071 } else {
2072 tmpType = &resultType;
2073 }
2074 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002075 SpvOpFOrdNotEqual, SpvOpINotEqual,
2076 SpvOpINotEqual, SpvOpLogicalNotEqual,
2077 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002078 *operandType, SpvOpAny, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002079 case Token::GT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002080 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002081 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2082 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002083 SpvOpUGreaterThan, SpvOpUndef, out);
2084 case Token::LT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002085 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002086 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002087 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
2088 case Token::GTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002089 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002090 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2091 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002092 SpvOpUGreaterThanEqual, SpvOpUndef, out);
2093 case Token::LTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002094 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002095 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2096 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002097 SpvOpULessThanEqual, SpvOpUndef, out);
2098 case Token::PLUS:
Ethan Nicholas0df21132018-07-10 09:37:51 -04002099 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2100 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2101 SkASSERT(b.fLeft->fType == b.fRight->fType);
2102 return this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2103 SpvOpFAdd, SpvOpIAdd, out);
2104 }
Greg Daniel64773e62016-11-22 09:44:03 -05002105 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002106 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2107 case Token::MINUS:
Ethan Nicholas0df21132018-07-10 09:37:51 -04002108 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2109 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2110 SkASSERT(b.fLeft->fType == b.fRight->fType);
2111 return this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2112 SpvOpFSub, SpvOpISub, out);
2113 }
Greg Daniel64773e62016-11-22 09:44:03 -05002114 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002115 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2116 case Token::STAR:
Greg Daniel64773e62016-11-22 09:44:03 -05002117 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002118 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002119 // matrix multiply
2120 SpvId result = this->nextId();
2121 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2122 lhs, rhs, out);
2123 return result;
2124 }
Greg Daniel64773e62016-11-22 09:44:03 -05002125 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002126 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2127 case Token::SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002128 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002129 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002130 case Token::PERCENT:
2131 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2132 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002133 case Token::SHL:
2134 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2135 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2136 SpvOpUndef, out);
2137 case Token::SHR:
2138 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2139 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2140 SpvOpUndef, out);
2141 case Token::BITWISEAND:
2142 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2143 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
2144 case Token::BITWISEOR:
2145 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2146 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
2147 case Token::BITWISEXOR:
2148 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2149 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002150 case Token::PLUSEQ: {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002151 SpvId result;
2152 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2153 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2154 SkASSERT(b.fLeft->fType == b.fRight->fType);
2155 result = this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2156 SpvOpFAdd, SpvOpIAdd, out);
2157 }
2158 else {
2159 result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002160 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002161 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002162 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002163 lvalue->store(result, out);
2164 return result;
2165 }
2166 case Token::MINUSEQ: {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002167 SpvId result;
2168 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2169 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2170 SkASSERT(b.fLeft->fType == b.fRight->fType);
2171 result = this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2172 SpvOpFSub, SpvOpISub, out);
2173 }
2174 else {
2175 result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002176 SpvOpISub, SpvOpISub, SpvOpUndef, out);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002177 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002178 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002179 lvalue->store(result, out);
2180 return result;
2181 }
2182 case Token::STAREQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002183 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002184 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002185 // matrix multiply
2186 SpvId result = this->nextId();
2187 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2188 lhs, rhs, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002189 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002190 lvalue->store(result, out);
2191 return result;
2192 }
Greg Daniel64773e62016-11-22 09:44:03 -05002193 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002194 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002195 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002196 lvalue->store(result, out);
2197 return result;
2198 }
2199 case Token::SLASHEQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002200 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002201 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002202 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002203 lvalue->store(result, out);
2204 return result;
2205 }
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002206 case Token::PERCENTEQ: {
2207 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2208 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002209 SkASSERT(lvalue);
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002210 lvalue->store(result, out);
2211 return result;
2212 }
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002213 case Token::SHLEQ: {
2214 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2215 SpvOpUndef, SpvOpShiftLeftLogical,
2216 SpvOpShiftLeftLogical, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002217 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002218 lvalue->store(result, out);
2219 return result;
2220 }
2221 case Token::SHREQ: {
2222 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2223 SpvOpUndef, SpvOpShiftRightArithmetic,
2224 SpvOpShiftRightLogical, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002225 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002226 lvalue->store(result, out);
2227 return result;
2228 }
2229 case Token::BITWISEANDEQ: {
2230 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2231 SpvOpUndef, SpvOpBitwiseAnd, SpvOpBitwiseAnd,
2232 SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002233 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002234 lvalue->store(result, out);
2235 return result;
2236 }
2237 case Token::BITWISEOREQ: {
2238 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2239 SpvOpUndef, SpvOpBitwiseOr, SpvOpBitwiseOr,
2240 SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002241 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002242 lvalue->store(result, out);
2243 return result;
2244 }
2245 case Token::BITWISEXOREQ: {
2246 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2247 SpvOpUndef, SpvOpBitwiseXor, SpvOpBitwiseXor,
2248 SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002249 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002250 lvalue->store(result, out);
2251 return result;
2252 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002253 default:
ethannicholasb3058bd2016-07-01 08:22:01 -07002254 ABORT("unsupported binary expression: %s", b.description().c_str());
2255 }
2256}
2257
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002258SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002259 SkASSERT(a.fOperator == Token::LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002260 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002261 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2262 SpvId lhs = this->writeExpression(*a.fLeft, out);
2263 SpvId rhsLabel = this->nextId();
2264 SpvId end = this->nextId();
2265 SpvId lhsBlock = fCurrentBlock;
2266 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2267 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2268 this->writeLabel(rhsLabel, out);
2269 SpvId rhs = this->writeExpression(*a.fRight, out);
2270 SpvId rhsBlock = fCurrentBlock;
2271 this->writeInstruction(SpvOpBranch, end, out);
2272 this->writeLabel(end, out);
2273 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002274 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002275 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002276 return result;
2277}
2278
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002279SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002280 SkASSERT(o.fOperator == Token::LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002281 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002282 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2283 SpvId lhs = this->writeExpression(*o.fLeft, out);
2284 SpvId rhsLabel = this->nextId();
2285 SpvId end = this->nextId();
2286 SpvId lhsBlock = fCurrentBlock;
2287 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2288 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2289 this->writeLabel(rhsLabel, out);
2290 SpvId rhs = this->writeExpression(*o.fRight, out);
2291 SpvId rhsBlock = fCurrentBlock;
2292 this->writeInstruction(SpvOpBranch, end, out);
2293 this->writeLabel(end, out);
2294 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002295 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002296 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002297 return result;
2298}
2299
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002300SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002301 SpvId test = this->writeExpression(*t.fTest, out);
Ethan Nicholas0f21c232018-07-23 09:25:40 -04002302 if (t.fIfTrue->fType.columns() == 1 && t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002303 // both true and false are constants, can just use OpSelect
2304 SpvId result = this->nextId();
2305 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2306 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
Greg Daniel64773e62016-11-22 09:44:03 -05002307 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002308 out);
2309 return result;
2310 }
Greg Daniel64773e62016-11-22 09:44:03 -05002311 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002312 // Adreno. Switched to storing the result in a temp variable as glslang does.
2313 SpvId var = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002314 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002315 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002316 SpvId trueLabel = this->nextId();
2317 SpvId falseLabel = this->nextId();
2318 SpvId end = this->nextId();
2319 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2320 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2321 this->writeLabel(trueLabel, out);
2322 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2323 this->writeInstruction(SpvOpBranch, end, out);
2324 this->writeLabel(falseLabel, out);
2325 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2326 this->writeInstruction(SpvOpBranch, end, out);
2327 this->writeLabel(end, out);
2328 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002329 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002330 return result;
2331}
2332
ethannicholasd598f792016-07-25 10:08:54 -07002333std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
Ethan Nicholas024301a2017-11-10 13:49:18 -05002334 if (type.isInteger()) {
Ethan Nicholas00543112018-07-31 09:44:36 -04002335 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002336 }
Ethan Nicholas024301a2017-11-10 13:49:18 -05002337 else if (type.isFloat()) {
Ethan Nicholas00543112018-07-31 09:44:36 -04002338 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002339 } else {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002340 ABORT("math is unsupported on type '%s'", type.name().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002341 }
2342}
2343
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002344SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002345 if (p.fOperator == Token::MINUS) {
2346 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002347 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002348 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002349 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002350 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002351 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002352 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2353 } else {
2354 ABORT("unsupported prefix expression %s", p.description().c_str());
2355 };
2356 return result;
2357 }
2358 switch (p.fOperator) {
2359 case Token::PLUS:
2360 return this->writeExpression(*p.fOperand, out);
2361 case Token::PLUSPLUS: {
2362 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002363 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002364 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2365 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002366 out);
2367 lv->store(result, out);
2368 return result;
2369 }
2370 case Token::MINUSMINUS: {
2371 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002372 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002373 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2374 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002375 out);
2376 lv->store(result, out);
2377 return result;
2378 }
ethannicholas5961bc92016-10-12 06:39:56 -07002379 case Token::LOGICALNOT: {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002380 SkASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002381 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002382 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002383 this->writeExpression(*p.fOperand, out), out);
2384 return result;
2385 }
ethannicholas5961bc92016-10-12 06:39:56 -07002386 case Token::BITWISENOT: {
2387 SpvId result = this->nextId();
2388 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2389 this->writeExpression(*p.fOperand, out), out);
2390 return result;
2391 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002392 default:
2393 ABORT("unsupported prefix expression: %s", p.description().c_str());
2394 }
2395}
2396
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002397SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002398 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2399 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002400 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002401 switch (p.fOperator) {
2402 case Token::PLUSPLUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002403 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002404 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2405 lv->store(temp, out);
2406 return result;
2407 }
2408 case Token::MINUSMINUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002409 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002410 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2411 lv->store(temp, out);
2412 return result;
2413 }
2414 default:
2415 ABORT("unsupported postfix expression %s", p.description().c_str());
2416 }
2417}
2418
ethannicholasf789b382016-08-03 12:43:36 -07002419SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002420 if (b.fValue) {
2421 if (fBoolTrue == 0) {
2422 fBoolTrue = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002423 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002424 fConstantBuffer);
2425 }
2426 return fBoolTrue;
2427 } else {
2428 if (fBoolFalse == 0) {
2429 fBoolFalse = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002430 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002431 fConstantBuffer);
2432 }
2433 return fBoolFalse;
2434 }
2435}
2436
ethannicholasf789b382016-08-03 12:43:36 -07002437SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholasd598f792016-07-25 10:08:54 -07002438 if (i.fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002439 auto entry = fIntConstants.find(i.fValue);
2440 if (entry == fIntConstants.end()) {
2441 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002442 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002443 fConstantBuffer);
2444 fIntConstants[i.fValue] = result;
2445 return result;
2446 }
2447 return entry->second;
2448 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002449 SkASSERT(i.fType == *fContext.fUInt_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002450 auto entry = fUIntConstants.find(i.fValue);
2451 if (entry == fUIntConstants.end()) {
2452 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002453 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002454 fConstantBuffer);
2455 fUIntConstants[i.fValue] = result;
2456 return result;
2457 }
2458 return entry->second;
2459 }
2460}
2461
ethannicholasf789b382016-08-03 12:43:36 -07002462SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002463 if (f.fType == *fContext.fFloat_Type || f.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002464 float value = (float) f.fValue;
2465 auto entry = fFloatConstants.find(value);
2466 if (entry == fFloatConstants.end()) {
2467 SpvId result = this->nextId();
2468 uint32_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002469 SkASSERT(sizeof(bits) == sizeof(value));
ethannicholasb3058bd2016-07-01 08:22:01 -07002470 memcpy(&bits, &value, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002471 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
ethannicholasb3058bd2016-07-01 08:22:01 -07002472 fConstantBuffer);
2473 fFloatConstants[value] = result;
2474 return result;
2475 }
2476 return entry->second;
2477 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002478 SkASSERT(f.fType == *fContext.fDouble_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002479 auto entry = fDoubleConstants.find(f.fValue);
2480 if (entry == fDoubleConstants.end()) {
2481 SpvId result = this->nextId();
2482 uint64_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002483 SkASSERT(sizeof(bits) == sizeof(f.fValue));
ethannicholasb3058bd2016-07-01 08:22:01 -07002484 memcpy(&bits, &f.fValue, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002485 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002486 bits & 0xffffffff, bits >> 32, fConstantBuffer);
2487 fDoubleConstants[f.fValue] = result;
2488 return result;
2489 }
2490 return entry->second;
2491 }
2492}
2493
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002494SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002495 SpvId result = fFunctionMap[&f];
Greg Daniel64773e62016-11-22 09:44:03 -05002496 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002497 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002498 this->writeInstruction(SpvOpName, result, f.fName, fNameBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002499 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002500 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002501 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002502 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002503 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002504 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2505 }
2506 return result;
2507}
2508
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002509SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2510 fVariableBuffer.reset();
ethannicholasb3058bd2016-07-01 08:22:01 -07002511 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2512 this->writeLabel(this->nextId(), out);
ethannicholasd598f792016-07-25 10:08:54 -07002513 if (f.fDeclaration.fName == "main") {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002514 write_stringstream(fGlobalInitializersBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002515 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002516 StringStream bodyBuffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04002517 this->writeBlock((Block&) *f.fBody, bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002518 write_stringstream(fVariableBuffer, out);
2519 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002520 if (fCurrentBlock) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002521 if (f.fDeclaration.fReturnType == *fContext.fVoid_Type) {
2522 this->writeInstruction(SpvOpReturn, out);
2523 } else {
2524 this->writeInstruction(SpvOpUnreachable, out);
2525 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002526 }
2527 this->writeInstruction(SpvOpFunctionEnd, out);
2528 return result;
2529}
2530
2531void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2532 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002533 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002534 fDecorationBuffer);
2535 }
2536 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002537 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002538 fDecorationBuffer);
2539 }
2540 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002541 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002542 fDecorationBuffer);
2543 }
2544 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002545 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002546 fDecorationBuffer);
2547 }
Greg Daniel64773e62016-11-22 09:44:03 -05002548 if (layout.fInputAttachmentIndex >= 0) {
2549 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2550 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002551 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002552 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002553 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002554 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002555 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002556 fDecorationBuffer);
2557 }
2558}
2559
2560void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2561 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002562 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002563 layout.fLocation, fDecorationBuffer);
2564 }
2565 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002566 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002567 layout.fBinding, fDecorationBuffer);
2568 }
2569 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002570 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002571 layout.fIndex, fDecorationBuffer);
2572 }
2573 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002574 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002575 layout.fSet, fDecorationBuffer);
2576 }
Greg Daniel64773e62016-11-22 09:44:03 -05002577 if (layout.fInputAttachmentIndex >= 0) {
2578 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2579 layout.fInputAttachmentIndex, fDecorationBuffer);
2580 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002581 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002582 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002583 layout.fBuiltin, fDecorationBuffer);
2584 }
2585}
2586
Ethan Nicholas81d15112018-07-13 12:48:50 -04002587static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2588 switch (m.fLayout.fPrimitive) {
2589 case Layout::kPoints_Primitive:
2590 *outSkInCount = 1;
2591 break;
2592 case Layout::kLines_Primitive:
2593 *outSkInCount = 2;
2594 break;
2595 case Layout::kLinesAdjacency_Primitive:
2596 *outSkInCount = 4;
2597 break;
2598 case Layout::kTriangles_Primitive:
2599 *outSkInCount = 3;
2600 break;
2601 case Layout::kTrianglesAdjacency_Primitive:
2602 *outSkInCount = 6;
2603 break;
2604 default:
2605 return;
2606 }
2607}
2608
ethannicholasf789b382016-08-03 12:43:36 -07002609SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas361941e2017-05-30 15:41:07 -04002610 bool isBuffer = (0 != (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag));
Ethan Nicholas39204fd2017-11-27 13:12:30 -05002611 bool pushConstant = (0 != (intf.fVariable.fModifiers.fLayout.fFlags &
2612 Layout::kPushConstant_Flag));
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002613 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2614 MemoryLayout(MemoryLayout::k430_Standard) :
2615 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002616 SpvId result = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002617 const Type* type = &intf.fVariable.fType;
Greg Daniele6ab9982018-08-22 13:56:32 +00002618 if (fProgram.fInputs.fRTHeight) {
2619 SkASSERT(fRTHeightStructId == (SpvId) -1);
2620 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002621 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002622 fRTHeightStructId = result;
2623 fRTHeightFieldIndex = fields.size();
2624 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002625 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002626 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002627 SpvId typeId;
2628 if (intf.fVariable.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2629 for (const auto& e : fProgram) {
2630 if (e.fKind == ProgramElement::kModifiers_Kind) {
2631 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholas81d15112018-07-13 12:48:50 -04002632 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002633 }
2634 }
2635 typeId = this->getType(Type("sk_in", Type::kArray_Kind, intf.fVariable.fType.componentType(),
2636 fSkInCount), memoryLayout);
2637 } else {
2638 typeId = this->getType(*type, memoryLayout);
2639 }
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002640 if (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag) {
2641 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
2642 } else {
2643 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
2644 }
ethannicholasd598f792016-07-25 10:08:54 -07002645 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002646 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002647 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002648 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002649 Layout layout = intf.fVariable.fModifiers.fLayout;
2650 if (intf.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
2651 layout.fSet = 0;
2652 }
2653 this->writeLayout(layout, result);
ethannicholasd598f792016-07-25 10:08:54 -07002654 fVariableMap[&intf.fVariable] = result;
Greg Daniele6ab9982018-08-22 13:56:32 +00002655 if (fProgram.fInputs.fRTHeight) {
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002656 delete type;
2657 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002658 return result;
2659}
2660
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002661void SPIRVCodeGenerator::writePrecisionModifier(const Modifiers& modifiers, SpvId id) {
2662 if ((modifiers.fFlags & Modifiers::kLowp_Flag) |
2663 (modifiers.fFlags & Modifiers::kMediump_Flag)) {
2664 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2665 }
2666}
2667
ethannicholas5961bc92016-10-12 06:39:56 -07002668#define BUILTIN_IGNORE 9999
Greg Daniel64773e62016-11-22 09:44:03 -05002669void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002670 OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002671 for (size_t i = 0; i < decl.fVars.size(); i++) {
2672 if (decl.fVars[i]->fKind == Statement::kNop_Kind) {
2673 continue;
2674 }
2675 const VarDeclaration& varDecl = (VarDeclaration&) *decl.fVars[i];
2676 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002677 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2678 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002679 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002680 Modifiers::kWriteOnly_Flag |
2681 Modifiers::kCoherent_Flag |
2682 Modifiers::kVolatile_Flag |
2683 Modifiers::kRestrict_Flag)));
ethannicholas5961bc92016-10-12 06:39:56 -07002684 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2685 continue;
2686 }
2687 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2688 kind != Program::kFragment_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002689 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
ethannicholas5961bc92016-10-12 06:39:56 -07002690 continue;
2691 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05002692 if (!var->fReadCount && !var->fWriteCount &&
ethannicholas14fe8cc2016-09-07 13:37:16 -07002693 !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
2694 Modifiers::kOut_Flag |
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002695 Modifiers::kUniform_Flag |
2696 Modifiers::kBuffer_Flag))) {
ethannicholasd598f792016-07-25 10:08:54 -07002697 // variable is dead and not an input / output var (the Vulkan debug layers complain if
2698 // we elide an interface var, even if it's dead)
ethannicholasb3058bd2016-07-01 08:22:01 -07002699 continue;
2700 }
2701 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002702 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002703 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002704 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002705 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002706 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
2707 if (var->fType.kind() == Type::kSampler_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002708 storageClass = SpvStorageClassUniformConstant;
2709 } else {
2710 storageClass = SpvStorageClassUniform;
2711 }
2712 } else {
2713 storageClass = SpvStorageClassPrivate;
2714 }
2715 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002716 fVariableMap[var] = id;
Ethan Nicholas5226b772018-05-03 16:20:41 -04002717 SpvId type;
2718 if (var->fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2719 type = this->getPointerType(Type("sk_in", Type::kArray_Kind,
2720 var->fType.componentType(), fSkInCount),
2721 storageClass);
2722 } else {
2723 type = this->getPointerType(var->fType, storageClass);
2724 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002725 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002726 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002727 this->writePrecisionModifier(var->fModifiers, id);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002728 if (varDecl.fValue) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002729 SkASSERT(!fCurrentBlock);
ethannicholasf789b382016-08-03 12:43:36 -07002730 fCurrentBlock = -1;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002731 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002732 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002733 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002734 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002735 this->writeLayout(var->fModifiers.fLayout, id);
Ethan Nicholas45b0f152017-07-24 14:36:40 -04002736 if (var->fModifiers.fFlags & Modifiers::kFlat_Flag) {
2737 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2738 }
2739 if (var->fModifiers.fFlags & Modifiers::kNoPerspective_Flag) {
2740 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2741 fDecorationBuffer);
2742 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002743 }
2744}
2745
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002746void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002747 for (const auto& stmt : decl.fVars) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002748 SkASSERT(stmt->fKind == Statement::kVarDeclaration_Kind);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002749 VarDeclaration& varDecl = (VarDeclaration&) *stmt;
2750 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002751 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2752 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002753 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002754 Modifiers::kWriteOnly_Flag |
2755 Modifiers::kCoherent_Flag |
2756 Modifiers::kVolatile_Flag |
2757 Modifiers::kRestrict_Flag)));
ethannicholasb3058bd2016-07-01 08:22:01 -07002758 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002759 fVariableMap[var] = id;
2760 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002761 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002762 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002763 if (varDecl.fValue) {
2764 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002765 this->writeInstruction(SpvOpStore, id, value, out);
2766 }
2767 }
2768}
2769
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002770void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002771 switch (s.fKind) {
Ethan Nicholascb670962017-04-20 19:31:52 -04002772 case Statement::kNop_Kind:
2773 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002774 case Statement::kBlock_Kind:
2775 this->writeBlock((Block&) s, out);
2776 break;
2777 case Statement::kExpression_Kind:
2778 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2779 break;
Greg Daniel64773e62016-11-22 09:44:03 -05002780 case Statement::kReturn_Kind:
ethannicholasb3058bd2016-07-01 08:22:01 -07002781 this->writeReturnStatement((ReturnStatement&) s, out);
2782 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002783 case Statement::kVarDeclarations_Kind:
2784 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002785 break;
2786 case Statement::kIf_Kind:
2787 this->writeIfStatement((IfStatement&) s, out);
2788 break;
2789 case Statement::kFor_Kind:
2790 this->writeForStatement((ForStatement&) s, out);
2791 break;
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002792 case Statement::kWhile_Kind:
2793 this->writeWhileStatement((WhileStatement&) s, out);
2794 break;
2795 case Statement::kDo_Kind:
2796 this->writeDoStatement((DoStatement&) s, out);
2797 break;
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002798 case Statement::kSwitch_Kind:
2799 this->writeSwitchStatement((SwitchStatement&) s, out);
2800 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002801 case Statement::kBreak_Kind:
2802 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2803 break;
2804 case Statement::kContinue_Kind:
2805 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2806 break;
2807 case Statement::kDiscard_Kind:
2808 this->writeInstruction(SpvOpKill, out);
2809 break;
2810 default:
2811 ABORT("unsupported statement: %s", s.description().c_str());
2812 }
2813}
2814
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002815void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002816 for (size_t i = 0; i < b.fStatements.size(); i++) {
2817 this->writeStatement(*b.fStatements[i], out);
2818 }
2819}
2820
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002821void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002822 SpvId test = this->writeExpression(*stmt.fTest, out);
2823 SpvId ifTrue = this->nextId();
2824 SpvId ifFalse = this->nextId();
2825 if (stmt.fIfFalse) {
2826 SpvId end = this->nextId();
2827 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2828 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2829 this->writeLabel(ifTrue, out);
2830 this->writeStatement(*stmt.fIfTrue, out);
2831 if (fCurrentBlock) {
2832 this->writeInstruction(SpvOpBranch, end, out);
2833 }
2834 this->writeLabel(ifFalse, out);
2835 this->writeStatement(*stmt.fIfFalse, out);
2836 if (fCurrentBlock) {
2837 this->writeInstruction(SpvOpBranch, end, out);
2838 }
2839 this->writeLabel(end, out);
2840 } else {
2841 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2842 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2843 this->writeLabel(ifTrue, out);
2844 this->writeStatement(*stmt.fIfTrue, out);
2845 if (fCurrentBlock) {
2846 this->writeInstruction(SpvOpBranch, ifFalse, out);
2847 }
2848 this->writeLabel(ifFalse, out);
2849 }
2850}
2851
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002852void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002853 if (f.fInitializer) {
2854 this->writeStatement(*f.fInitializer, out);
2855 }
2856 SpvId header = this->nextId();
2857 SpvId start = this->nextId();
2858 SpvId body = this->nextId();
2859 SpvId next = this->nextId();
2860 fContinueTarget.push(next);
2861 SpvId end = this->nextId();
2862 fBreakTarget.push(end);
2863 this->writeInstruction(SpvOpBranch, header, out);
2864 this->writeLabel(header, out);
2865 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002866 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002867 this->writeLabel(start, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002868 if (f.fTest) {
2869 SpvId test = this->writeExpression(*f.fTest, out);
2870 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2871 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002872 this->writeLabel(body, out);
2873 this->writeStatement(*f.fStatement, out);
2874 if (fCurrentBlock) {
2875 this->writeInstruction(SpvOpBranch, next, out);
2876 }
2877 this->writeLabel(next, out);
2878 if (f.fNext) {
2879 this->writeExpression(*f.fNext, out);
2880 }
2881 this->writeInstruction(SpvOpBranch, header, out);
2882 this->writeLabel(end, out);
2883 fBreakTarget.pop();
2884 fContinueTarget.pop();
2885}
2886
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002887void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002888 // We believe the while loop code below will work, but Skia doesn't actually use them and
2889 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2890 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2891 // message, simply remove the error call below to see whether our while loop support actually
2892 // works.
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002893 fErrors.error(w.fOffset, "internal error: while loop support has been disabled in SPIR-V, "
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002894 "see SkSLSPIRVCodeGenerator.cpp for details");
2895
2896 SpvId header = this->nextId();
2897 SpvId start = this->nextId();
2898 SpvId body = this->nextId();
2899 fContinueTarget.push(start);
2900 SpvId end = this->nextId();
2901 fBreakTarget.push(end);
2902 this->writeInstruction(SpvOpBranch, header, out);
2903 this->writeLabel(header, out);
2904 this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out);
2905 this->writeInstruction(SpvOpBranch, start, out);
2906 this->writeLabel(start, out);
2907 SpvId test = this->writeExpression(*w.fTest, out);
2908 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2909 this->writeLabel(body, out);
2910 this->writeStatement(*w.fStatement, out);
2911 if (fCurrentBlock) {
2912 this->writeInstruction(SpvOpBranch, start, out);
2913 }
2914 this->writeLabel(end, out);
2915 fBreakTarget.pop();
2916 fContinueTarget.pop();
2917}
2918
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002919void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002920 // We believe the do loop code below will work, but Skia doesn't actually use them and
2921 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2922 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2923 // message, simply remove the error call below to see whether our do loop support actually
2924 // works.
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002925 fErrors.error(d.fOffset, "internal error: do loop support has been disabled in SPIR-V, see "
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002926 "SkSLSPIRVCodeGenerator.cpp for details");
2927
2928 SpvId header = this->nextId();
2929 SpvId start = this->nextId();
2930 SpvId next = this->nextId();
2931 fContinueTarget.push(next);
2932 SpvId end = this->nextId();
2933 fBreakTarget.push(end);
2934 this->writeInstruction(SpvOpBranch, header, out);
2935 this->writeLabel(header, out);
2936 this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out);
2937 this->writeInstruction(SpvOpBranch, start, out);
2938 this->writeLabel(start, out);
2939 this->writeStatement(*d.fStatement, out);
2940 if (fCurrentBlock) {
2941 this->writeInstruction(SpvOpBranch, next, out);
2942 }
2943 this->writeLabel(next, out);
2944 SpvId test = this->writeExpression(*d.fTest, out);
2945 this->writeInstruction(SpvOpBranchConditional, test, start, end, out);
2946 this->writeLabel(end, out);
2947 fBreakTarget.pop();
2948 fContinueTarget.pop();
2949}
2950
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002951void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
2952 SpvId value = this->writeExpression(*s.fValue, out);
2953 std::vector<SpvId> labels;
2954 SpvId end = this->nextId();
2955 SpvId defaultLabel = end;
2956 fBreakTarget.push(end);
2957 int size = 3;
2958 for (const auto& c : s.fCases) {
2959 SpvId label = this->nextId();
2960 labels.push_back(label);
2961 if (c->fValue) {
2962 size += 2;
2963 } else {
2964 defaultLabel = label;
2965 }
2966 }
2967 labels.push_back(end);
2968 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2969 this->writeOpCode(SpvOpSwitch, size, out);
2970 this->writeWord(value, out);
2971 this->writeWord(defaultLabel, out);
2972 for (size_t i = 0; i < s.fCases.size(); ++i) {
2973 if (!s.fCases[i]->fValue) {
2974 continue;
2975 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002976 SkASSERT(s.fCases[i]->fValue->fKind == Expression::kIntLiteral_Kind);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002977 this->writeWord(((IntLiteral&) *s.fCases[i]->fValue).fValue, out);
2978 this->writeWord(labels[i], out);
2979 }
2980 for (size_t i = 0; i < s.fCases.size(); ++i) {
2981 this->writeLabel(labels[i], out);
2982 for (const auto& stmt : s.fCases[i]->fStatements) {
2983 this->writeStatement(*stmt, out);
2984 }
2985 if (fCurrentBlock) {
2986 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
2987 }
2988 }
2989 this->writeLabel(end, out);
2990 fBreakTarget.pop();
2991}
2992
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002993void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002994 if (r.fExpression) {
Greg Daniel64773e62016-11-22 09:44:03 -05002995 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
ethannicholasb3058bd2016-07-01 08:22:01 -07002996 out);
2997 } else {
2998 this->writeInstruction(SpvOpReturn, out);
2999 }
3000}
3001
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003002void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003003 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003004 int invocations = 1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003005 for (const auto& e : fProgram) {
3006 if (e.fKind == ProgramElement::kModifiers_Kind) {
3007 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003008 if (m.fFlags & Modifiers::kIn_Flag) {
3009 if (m.fLayout.fInvocations != -1) {
3010 invocations = m.fLayout.fInvocations;
3011 }
3012 SpvId input;
3013 switch (m.fLayout.fPrimitive) {
3014 case Layout::kPoints_Primitive:
3015 input = SpvExecutionModeInputPoints;
3016 break;
3017 case Layout::kLines_Primitive:
3018 input = SpvExecutionModeInputLines;
3019 break;
3020 case Layout::kLinesAdjacency_Primitive:
3021 input = SpvExecutionModeInputLinesAdjacency;
3022 break;
3023 case Layout::kTriangles_Primitive:
3024 input = SpvExecutionModeTriangles;
3025 break;
3026 case Layout::kTrianglesAdjacency_Primitive:
3027 input = SpvExecutionModeInputTrianglesAdjacency;
3028 break;
3029 default:
3030 input = 0;
3031 break;
3032 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003033 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003034 if (input) {
3035 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3036 }
3037 } else if (m.fFlags & Modifiers::kOut_Flag) {
3038 SpvId output;
3039 switch (m.fLayout.fPrimitive) {
3040 case Layout::kPoints_Primitive:
3041 output = SpvExecutionModeOutputPoints;
3042 break;
3043 case Layout::kLineStrip_Primitive:
3044 output = SpvExecutionModeOutputLineStrip;
3045 break;
3046 case Layout::kTriangleStrip_Primitive:
3047 output = SpvExecutionModeOutputTriangleStrip;
3048 break;
3049 default:
3050 output = 0;
3051 break;
3052 }
3053 if (output) {
3054 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3055 }
3056 if (m.fLayout.fMaxVertices != -1) {
3057 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3058 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3059 out);
3060 }
3061 }
3062 }
3063 }
3064 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3065 invocations, out);
3066}
3067
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003068void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003069 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003070 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003071 std::set<SpvId> interfaceVars;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003072 // assign IDs to functions, determine sk_in size
3073 int skInSize = -1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003074 for (const auto& e : program) {
3075 switch (e.fKind) {
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003076 case ProgramElement::kFunction_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003077 FunctionDefinition& f = (FunctionDefinition&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003078 fFunctionMap[&f.fDeclaration] = this->nextId();
3079 break;
3080 }
3081 case ProgramElement::kModifiers_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003082 Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003083 if (m.fFlags & Modifiers::kIn_Flag) {
3084 switch (m.fLayout.fPrimitive) {
3085 case Layout::kPoints_Primitive: // break
3086 case Layout::kLines_Primitive:
3087 skInSize = 1;
3088 break;
3089 case Layout::kLinesAdjacency_Primitive: // break
3090 skInSize = 2;
3091 break;
3092 case Layout::kTriangles_Primitive: // break
3093 case Layout::kTrianglesAdjacency_Primitive:
3094 skInSize = 3;
3095 break;
3096 default:
3097 break;
3098 }
3099 }
3100 break;
3101 }
3102 default:
3103 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003104 }
3105 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003106 for (const auto& e : program) {
3107 if (e.fKind == ProgramElement::kInterfaceBlock_Kind) {
3108 InterfaceBlock& intf = (InterfaceBlock&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003109 if (SK_IN_BUILTIN == intf.fVariable.fModifiers.fLayout.fBuiltin) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003110 SkASSERT(skInSize != -1);
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003111 intf.fSizes.emplace_back(new IntLiteral(fContext, -1, skInSize));
3112 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003113 SpvId id = this->writeInterfaceBlock(intf);
Ethan Nicholas16c11962018-03-16 12:20:54 -04003114 if (((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
3115 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) &&
3116 intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003117 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003118 }
3119 }
3120 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003121 for (const auto& e : program) {
3122 if (e.fKind == ProgramElement::kVar_Kind) {
3123 this->writeGlobalVars(program.fKind, ((VarDeclarations&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003124 }
3125 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003126 for (const auto& e : program) {
3127 if (e.fKind == ProgramElement::kFunction_Kind) {
3128 this->writeFunction(((FunctionDefinition&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003129 }
3130 }
ethannicholasd598f792016-07-25 10:08:54 -07003131 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003132 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07003133 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003134 main = entry.first;
3135 }
3136 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003137 SkASSERT(main);
ethannicholasb3058bd2016-07-01 08:22:01 -07003138 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003139 const Variable* var = entry.first;
Ethan Nicholas81d15112018-07-13 12:48:50 -04003140 int builtin = var->fModifiers.fLayout.fBuiltin;
Greg Daniel64773e62016-11-22 09:44:03 -05003141 if (var->fStorage == Variable::kGlobal_Storage &&
Ethan Nicholas16c11962018-03-16 12:20:54 -04003142 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
Ethan Nicholas81d15112018-07-13 12:48:50 -04003143 (var->fModifiers.fFlags & Modifiers::kOut_Flag)) &&
3144 builtin != SK_OUT_BUILTIN &&
3145 builtin != SK_INVOCATIONID_BUILTIN) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003146 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003147 }
3148 }
3149 this->writeCapabilities(out);
3150 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3151 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003152 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->fName.fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003153 (int32_t) interfaceVars.size(), out);
3154 switch (program.fKind) {
3155 case Program::kVertex_Kind:
3156 this->writeWord(SpvExecutionModelVertex, out);
3157 break;
3158 case Program::kFragment_Kind:
3159 this->writeWord(SpvExecutionModelFragment, out);
3160 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003161 case Program::kGeometry_Kind:
3162 this->writeWord(SpvExecutionModelGeometry, out);
3163 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003164 default:
3165 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003166 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003167 SpvId entryPoint = fFunctionMap[main];
3168 this->writeWord(entryPoint, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003169 this->writeString(main->fName.fChars, main->fName.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003170 for (int var : interfaceVars) {
3171 this->writeWord(var, out);
3172 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003173 if (program.fKind == Program::kGeometry_Kind) {
3174 this->writeGeometryShaderExecutionMode(entryPoint, out);
3175 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003176 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003177 this->writeInstruction(SpvOpExecutionMode,
3178 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003179 SpvExecutionModeOriginUpperLeft,
3180 out);
3181 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003182 for (const auto& e : program) {
3183 if (e.fKind == ProgramElement::kExtension_Kind) {
3184 this->writeInstruction(SpvOpSourceExtension, ((Extension&) e).fName.c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003185 }
3186 }
Greg Daniel64773e62016-11-22 09:44:03 -05003187
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003188 write_stringstream(fExtraGlobalsBuffer, out);
3189 write_stringstream(fNameBuffer, out);
3190 write_stringstream(fDecorationBuffer, out);
3191 write_stringstream(fConstantBuffer, out);
3192 write_stringstream(fExternalFunctionsBuffer, out);
3193 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003194}
3195
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003196bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003197 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003198 this->writeWord(SpvMagicNumber, *fOut);
3199 this->writeWord(SpvVersion, *fOut);
3200 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003201 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003202 this->writeInstructions(fProgram, buffer);
3203 this->writeWord(fIdCount, *fOut);
3204 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003205 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003206 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003207}
3208
3209}