blob: 77d88052c469dba10331189bfbc1381a13283052 [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);
Chris Dalton09212192018-11-13 15:07:24 -0500103 fIntrinsicMap[String("fwidth")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFwidth,
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) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500436 if (type.isFloat()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400437 return *fContext.fFloat_Type;
438 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500439 if (type.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400440 return *fContext.fInt_Type;
441 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500442 if (type.isUnsigned()) {
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);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500475 } else if (type == *fContext.fInt_Type || type == *fContext.fShort_Type ||
476 type == *fContext.fIntLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700477 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500478 } else if (type == *fContext.fUInt_Type || type == *fContext.fUShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700479 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500480 } else if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type ||
481 type == *fContext.fFloatLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700482 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -0700483 } else if (type == *fContext.fDouble_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700484 this->writeInstruction(SpvOpTypeFloat, result, 64, fConstantBuffer);
485 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400486 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700487 }
488 break;
489 case Type::kVector_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500490 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800491 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700492 type.columns(), fConstantBuffer);
493 break;
494 case Type::kMatrix_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500495 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800496 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700497 type.columns(), fConstantBuffer);
498 break;
499 case Type::kStruct_Kind:
ethannicholas8ac838d2016-11-22 08:39:36 -0800500 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700501 break;
502 case Type::kArray_Kind: {
503 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700504 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500505 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800506 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700507 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500508 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400509 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800510 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700511 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400512 SkASSERT(false); // we shouldn't have any runtime-sized arrays right now
Greg Daniel64773e62016-11-22 09:44:03 -0500513 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800514 this->getType(type.componentType(), layout),
515 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400516 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
517 (int32_t) layout.stride(type),
518 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700519 }
520 break;
521 }
522 case Type::kSampler_Kind: {
Greg Daniel64773e62016-11-22 09:44:03 -0500523 SpvId image = result;
524 if (SpvDimSubpassData != type.dimensions()) {
525 image = this->nextId();
526 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400527 if (SpvDimBuffer == type.dimensions()) {
528 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
529 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800530 this->writeInstruction(SpvOpTypeImage, image,
531 this->getType(*fContext.fFloat_Type, layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700532 type.dimensions(), type.isDepth(), type.isArrayed(),
Greg Daniel64773e62016-11-22 09:44:03 -0500533 type.isMultisampled(), type.isSampled() ? 1 : 2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700534 SpvImageFormatUnknown, fConstantBuffer);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400535 fImageTypeMap[key] = image;
Greg Daniel64773e62016-11-22 09:44:03 -0500536 if (SpvDimSubpassData != type.dimensions()) {
537 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
538 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700539 break;
540 }
541 default:
ethannicholasd598f792016-07-25 10:08:54 -0700542 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700543 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
544 } else {
545 ABORT("invalid type: %s", type.description().c_str());
546 }
547 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800548 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700549 return result;
550 }
551 return entry->second;
552}
553
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400554SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400555 SkASSERT(type.kind() == Type::kSampler_Kind);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400556 this->getType(type);
557 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400558 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400559 return fImageTypeMap[key];
560}
561
ethannicholasd598f792016-07-25 10:08:54 -0700562SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400563 String key = function.fReturnType.description() + "(";
564 String separator;
ethannicholasd598f792016-07-25 10:08:54 -0700565 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700566 key += separator;
567 separator = ", ";
ethannicholasd598f792016-07-25 10:08:54 -0700568 key += function.fParameters[i]->fType.description();
ethannicholasb3058bd2016-07-01 08:22:01 -0700569 }
570 key += ")";
571 auto entry = fTypeMap.find(key);
572 if (entry == fTypeMap.end()) {
573 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -0700574 int32_t length = 3 + (int32_t) function.fParameters.size();
575 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700576 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -0700577 for (size_t i = 0; i < function.fParameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500578 // glslang seems to treat all function arguments as pointers whether they need to be or
579 // not. I was initially puzzled by this until I ran bizarre failures with certain
580 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700581 // failure case:
582 //
583 // void sphere(float x) {
584 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500585 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700586 // void map() {
587 // sphere(1.0);
588 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500589 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700590 // void main() {
591 // for (int i = 0; i < 1; i++) {
592 // map();
593 // }
594 // }
595 //
Greg Daniel64773e62016-11-22 09:44:03 -0500596 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
597 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700598 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
599 // the spec makes this make sense.
600// if (is_out(function->fParameters[i])) {
ethannicholasd598f792016-07-25 10:08:54 -0700601 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -0700602 SpvStorageClassFunction));
603// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700604// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700605// }
606 }
607 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
608 this->writeWord(result, fConstantBuffer);
609 this->writeWord(returnType, fConstantBuffer);
610 for (SpvId id : parameterTypes) {
611 this->writeWord(id, fConstantBuffer);
612 }
613 fTypeMap[key] = result;
614 return result;
615 }
616 return entry->second;
617}
618
ethannicholas8ac838d2016-11-22 08:39:36 -0800619SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
620 return this->getPointerType(type, fDefaultLayout, storageClass);
621}
622
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400623SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700624 SpvStorageClass_ storageClass) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400625 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400626 String key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700627 auto entry = fTypeMap.find(key);
628 if (entry == fTypeMap.end()) {
629 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500630 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700631 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700632 fTypeMap[key] = result;
633 return result;
634 }
635 return entry->second;
636}
637
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400638SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700639 switch (expr.fKind) {
640 case Expression::kBinary_Kind:
641 return this->writeBinaryExpression((BinaryExpression&) expr, out);
642 case Expression::kBoolLiteral_Kind:
643 return this->writeBoolLiteral((BoolLiteral&) expr);
644 case Expression::kConstructor_Kind:
645 return this->writeConstructor((Constructor&) expr, out);
646 case Expression::kIntLiteral_Kind:
647 return this->writeIntLiteral((IntLiteral&) expr);
648 case Expression::kFieldAccess_Kind:
649 return this->writeFieldAccess(((FieldAccess&) expr), out);
650 case Expression::kFloatLiteral_Kind:
651 return this->writeFloatLiteral(((FloatLiteral&) expr));
652 case Expression::kFunctionCall_Kind:
653 return this->writeFunctionCall((FunctionCall&) expr, out);
654 case Expression::kPrefix_Kind:
655 return this->writePrefixExpression((PrefixExpression&) expr, out);
656 case Expression::kPostfix_Kind:
657 return this->writePostfixExpression((PostfixExpression&) expr, out);
658 case Expression::kSwizzle_Kind:
659 return this->writeSwizzle((Swizzle&) expr, out);
660 case Expression::kVariableReference_Kind:
661 return this->writeVariableReference((VariableReference&) expr, out);
662 case Expression::kTernary_Kind:
663 return this->writeTernaryExpression((TernaryExpression&) expr, out);
664 case Expression::kIndex_Kind:
665 return this->writeIndexExpression((IndexExpression&) expr, out);
666 default:
667 ABORT("unsupported expression: %s", expr.description().c_str());
668 }
669 return -1;
670}
671
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400672SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700673 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400674 SkASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -0700675 int32_t intrinsicId;
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400676 if (c.fArguments.size() > 0) {
677 const Type& type = c.fArguments[0]->fType;
678 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
679 intrinsicId = std::get<1>(intrinsic->second);
680 } else if (is_signed(fContext, type)) {
681 intrinsicId = std::get<2>(intrinsic->second);
682 } else if (is_unsigned(fContext, type)) {
683 intrinsicId = std::get<3>(intrinsic->second);
684 } else if (is_bool(fContext, type)) {
685 intrinsicId = std::get<4>(intrinsic->second);
686 } else {
687 intrinsicId = std::get<1>(intrinsic->second);
688 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700689 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400690 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700691 }
692 switch (std::get<0>(intrinsic->second)) {
693 case kGLSL_STD_450_IntrinsicKind: {
694 SpvId result = this->nextId();
695 std::vector<SpvId> arguments;
696 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400697 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
698 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
699 } else {
700 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
701 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700702 }
703 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700704 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700705 this->writeWord(result, out);
706 this->writeWord(fGLSLExtendedInstructions, out);
707 this->writeWord(intrinsicId, out);
708 for (SpvId id : arguments) {
709 this->writeWord(id, out);
710 }
711 return result;
712 }
713 case kSPIRV_IntrinsicKind: {
714 SpvId result = this->nextId();
715 std::vector<SpvId> arguments;
716 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400717 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
718 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
719 } else {
720 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
721 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700722 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400723 if (c.fType != *fContext.fVoid_Type) {
724 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
725 this->writeWord(this->getType(c.fType), out);
726 this->writeWord(result, out);
727 } else {
728 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
729 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700730 for (SpvId id : arguments) {
731 this->writeWord(id, out);
732 }
733 return result;
734 }
735 case kSpecial_IntrinsicKind:
736 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
737 default:
738 ABORT("unsupported intrinsic kind");
739 }
740}
741
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500742std::vector<SpvId> SPIRVCodeGenerator::vectorize(
743 const std::vector<std::unique_ptr<Expression>>& args,
744 OutputStream& out) {
745 int vectorSize = 0;
746 for (const auto& a : args) {
747 if (a->fType.kind() == Type::kVector_Kind) {
748 if (vectorSize) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400749 SkASSERT(a->fType.columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500750 }
751 else {
752 vectorSize = a->fType.columns();
753 }
754 }
755 }
756 std::vector<SpvId> result;
757 for (const auto& a : args) {
758 SpvId raw = this->writeExpression(*a, out);
759 if (vectorSize && a->fType.kind() == Type::kScalar_Kind) {
760 SpvId vector = this->nextId();
761 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
762 this->writeWord(this->getType(a->fType.toCompound(fContext, vectorSize, 1)), out);
763 this->writeWord(vector, out);
764 for (int i = 0; i < vectorSize; i++) {
765 this->writeWord(raw, out);
766 }
767 result.push_back(vector);
768 } else {
769 result.push_back(raw);
770 }
771 }
772 return result;
773}
774
775void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
776 SpvId signedInst, SpvId unsignedInst,
777 const std::vector<SpvId>& args,
778 OutputStream& out) {
779 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
780 this->writeWord(this->getType(type), out);
781 this->writeWord(id, out);
782 this->writeWord(fGLSLExtendedInstructions, out);
783
784 if (is_float(fContext, type)) {
785 this->writeWord(floatInst, out);
786 } else if (is_signed(fContext, type)) {
787 this->writeWord(signedInst, out);
788 } else if (is_unsigned(fContext, type)) {
789 this->writeWord(unsignedInst, out);
790 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400791 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500792 }
793 for (SpvId a : args) {
794 this->writeWord(a, out);
795 }
796}
797
Greg Daniel64773e62016-11-22 09:44:03 -0500798SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400799 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700800 SpvId result = this->nextId();
801 switch (kind) {
802 case kAtan_SpecialIntrinsic: {
803 std::vector<SpvId> arguments;
804 for (size_t i = 0; i < c.fArguments.size(); i++) {
805 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
806 }
807 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700808 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700809 this->writeWord(result, out);
810 this->writeWord(fGLSLExtendedInstructions, out);
811 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
812 for (SpvId id : arguments) {
813 this->writeWord(id, out);
814 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400815 break;
816 }
817 case kSubpassLoad_SpecialIntrinsic: {
818 SpvId img = this->writeExpression(*c.fArguments[0], out);
819 std::vector<std::unique_ptr<Expression>> args;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700820 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
821 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
822 Constructor ctor(-1, *fContext.fFloat2_Type, std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400823 SpvId coords = this->writeConstantVector(ctor);
824 if (1 == c.fArguments.size()) {
825 this->writeInstruction(SpvOpImageRead,
826 this->getType(c.fType),
827 result,
828 img,
829 coords,
830 out);
831 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400832 SkASSERT(2 == c.fArguments.size());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400833 SpvId sample = this->writeExpression(*c.fArguments[1], out);
834 this->writeInstruction(SpvOpImageRead,
835 this->getType(c.fType),
836 result,
837 img,
838 coords,
839 SpvImageOperandsSampleMask,
840 sample,
841 out);
842 }
843 break;
844 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700845 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500846 SpvOp_ op = SpvOpImageSampleImplicitLod;
847 switch (c.fArguments[0]->fType.dimensions()) {
848 case SpvDim1D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400849 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500850 op = SpvOpImageSampleProjImplicitLod;
851 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400852 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500853 }
854 break;
855 case SpvDim2D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400856 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500857 op = SpvOpImageSampleProjImplicitLod;
858 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400859 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500860 }
861 break;
862 case SpvDim3D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400863 if (c.fArguments[1]->fType == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500864 op = SpvOpImageSampleProjImplicitLod;
865 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400866 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500867 }
868 break;
869 case SpvDimCube: // fall through
870 case SpvDimRect: // fall through
871 case SpvDimBuffer: // fall through
872 case SpvDimSubpassData:
873 break;
874 }
ethannicholasd598f792016-07-25 10:08:54 -0700875 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700876 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
877 SpvId uv = this->writeExpression(*c.fArguments[1], out);
878 if (c.fArguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500879 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700880 SpvImageOperandsBiasMask,
881 this->writeExpression(*c.fArguments[2], out),
882 out);
883 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400884 SkASSERT(c.fArguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500885 if (fProgram.fSettings.fSharpenTextures) {
886 FloatLiteral lodBias(fContext, -1, -0.5);
887 this->writeInstruction(op, type, result, sampler, uv,
888 SpvImageOperandsBiasMask,
889 this->writeFloatLiteral(lodBias),
890 out);
891 } else {
892 this->writeInstruction(op, type, result, sampler, uv,
893 out);
894 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700895 }
896 break;
897 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500898 case kMod_SpecialIntrinsic: {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500899 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400900 SkASSERT(args.size() == 2);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500901 const Type& operandType = c.fArguments[0]->fType;
902 SpvOp_ op;
903 if (is_float(fContext, operandType)) {
904 op = SpvOpFMod;
905 } else if (is_signed(fContext, operandType)) {
906 op = SpvOpSMod;
907 } else if (is_unsigned(fContext, operandType)) {
908 op = SpvOpUMod;
909 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400910 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500911 return 0;
912 }
913 this->writeOpCode(op, 5, out);
914 this->writeWord(this->getType(operandType), out);
915 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500916 this->writeWord(args[0], out);
917 this->writeWord(args[1], out);
918 break;
919 }
920 case kClamp_SpecialIntrinsic: {
921 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400922 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500923 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
924 GLSLstd450UClamp, args, out);
925 break;
926 }
927 case kMax_SpecialIntrinsic: {
928 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400929 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500930 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMax, GLSLstd450SMax,
931 GLSLstd450UMax, args, out);
932 break;
933 }
934 case kMin_SpecialIntrinsic: {
935 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400936 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500937 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMin, GLSLstd450SMin,
938 GLSLstd450UMin, args, out);
939 break;
940 }
941 case kMix_SpecialIntrinsic: {
942 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400943 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500944 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMix, SpvOpUndef,
945 SpvOpUndef, args, out);
946 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500947 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400948 case kSaturate_SpecialIntrinsic: {
949 SkASSERT(c.fArguments.size() == 1);
950 std::vector<std::unique_ptr<Expression>> finalArgs;
951 finalArgs.push_back(c.fArguments[0]->clone());
952 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 0));
953 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 1));
954 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
955 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
956 GLSLstd450UClamp, spvArgs, out);
957 break;
958 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700959 }
960 return result;
961}
962
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400963SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700964 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -0700965 if (entry == fFunctionMap.end()) {
966 return this->writeIntrinsicCall(c, out);
967 }
968 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
969 std::vector<std::tuple<SpvId, SpvId, std::unique_ptr<LValue>>> lvalues;
970 std::vector<SpvId> arguments;
971 for (size_t i = 0; i < c.fArguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500972 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -0700973 // passed directly
974 SpvId tmpVar;
975 // if we need a temporary var to store this argument, this is the value to store in the var
976 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -0700977 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700978 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
979 SpvId ptr = lv->getPointer();
980 if (ptr) {
981 arguments.push_back(ptr);
982 continue;
983 } else {
984 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
985 // copy it into a temp, call the function, read the value out of the temp, and then
986 // update the lvalue.
987 tmpValueId = lv->load(out);
988 tmpVar = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -0700989 lvalues.push_back(std::make_tuple(tmpVar, this->getType(c.fArguments[i]->fType),
ethannicholasb3058bd2016-07-01 08:22:01 -0700990 std::move(lv)));
991 }
992 } else {
993 // see getFunctionType for an explanation of why we're always using pointer parameters
994 tmpValueId = this->writeExpression(*c.fArguments[i], out);
995 tmpVar = this->nextId();
996 }
Greg Daniel64773e62016-11-22 09:44:03 -0500997 this->writeInstruction(SpvOpVariable,
998 this->getPointerType(c.fArguments[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -0700999 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001000 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001001 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001002 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001003 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1004 arguments.push_back(tmpVar);
1005 }
1006 SpvId result = this->nextId();
1007 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001008 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001009 this->writeWord(result, out);
1010 this->writeWord(entry->second, out);
1011 for (SpvId id : arguments) {
1012 this->writeWord(id, out);
1013 }
1014 // now that the call is complete, we may need to update some lvalues with the new values of out
1015 // arguments
1016 for (const auto& tuple : lvalues) {
1017 SpvId load = this->nextId();
1018 this->writeInstruction(SpvOpLoad, std::get<1>(tuple), load, std::get<0>(tuple), out);
1019 std::get<2>(tuple)->store(load, out);
1020 }
1021 return result;
1022}
1023
ethannicholasf789b382016-08-03 12:43:36 -07001024SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001025 SkASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001026 SpvId result = this->nextId();
1027 std::vector<SpvId> arguments;
1028 for (size_t i = 0; i < c.fArguments.size(); i++) {
1029 arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1030 }
ethannicholasd598f792016-07-25 10:08:54 -07001031 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001032 if (c.fArguments.size() == 1) {
1033 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001034 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001035 this->writeWord(type, fConstantBuffer);
1036 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001037 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001038 this->writeWord(arguments[0], fConstantBuffer);
1039 }
1040 } else {
Greg Daniel64773e62016-11-22 09:44:03 -05001041 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001042 fConstantBuffer);
1043 this->writeWord(type, fConstantBuffer);
1044 this->writeWord(result, fConstantBuffer);
1045 for (SpvId id : arguments) {
1046 this->writeWord(id, fConstantBuffer);
1047 }
1048 }
1049 return result;
1050}
1051
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001052SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001053 SkASSERT(c.fType.isFloat());
1054 SkASSERT(c.fArguments.size() == 1);
1055 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001056 SpvId result = this->nextId();
1057 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001058 if (c.fArguments[0]->fType.isSigned()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001059 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001060 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001061 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001062 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Greg Daniel64773e62016-11-22 09:44:03 -05001063 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001064 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001065 }
1066 return result;
1067}
1068
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001069SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001070 SkASSERT(c.fType.isSigned());
1071 SkASSERT(c.fArguments.size() == 1);
1072 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001073 SpvId result = this->nextId();
1074 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001075 if (c.fArguments[0]->fType.isFloat()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001076 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001077 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001078 }
1079 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001080 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001081 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001082 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001083 }
1084 return result;
1085}
1086
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001087SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001088 SkASSERT(c.fType.isUnsigned());
1089 SkASSERT(c.fArguments.size() == 1);
1090 SkASSERT(c.fArguments[0]->fType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001091 SpvId result = this->nextId();
1092 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001093 if (c.fArguments[0]->fType.isFloat()) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001094 this->writeInstruction(SpvOpConvertFToU, this->getType(c.fType), result, parameter,
1095 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001096 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001097 SkASSERT(c.fArguments[0]->fType.isSigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001098 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
1099 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001100 }
1101 return result;
1102}
1103
Ethan Nicholas84645e32017-02-09 13:57:14 -05001104void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001105 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001106 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001107 SpvId zeroId = this->writeFloatLiteral(zero);
1108 std::vector<SpvId> columnIds;
1109 for (int column = 0; column < type.columns(); column++) {
1110 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1111 out);
1112 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1113 out);
1114 SpvId columnId = this->nextId();
1115 this->writeWord(columnId, out);
1116 columnIds.push_back(columnId);
1117 for (int row = 0; row < type.columns(); row++) {
1118 this->writeWord(row == column ? diagonal : zeroId, out);
1119 }
1120 }
1121 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1122 out);
1123 this->writeWord(this->getType(type), out);
1124 this->writeWord(id, out);
1125 for (SpvId id : columnIds) {
1126 this->writeWord(id, out);
1127 }
1128}
1129
1130void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001131 const Type& dstType, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001132 SkASSERT(srcType.kind() == Type::kMatrix_Kind);
1133 SkASSERT(dstType.kind() == Type::kMatrix_Kind);
1134 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001135 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1136 srcType.rows(),
1137 1));
1138 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1139 dstType.rows(),
1140 1));
1141 SpvId zeroId;
1142 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001143 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001144 zeroId = this->writeFloatLiteral(zero);
1145 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001146 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001147 zeroId = this->writeIntLiteral(zero);
1148 } else {
1149 ABORT("unsupported matrix component type");
1150 }
1151 SpvId zeroColumn = 0;
1152 SpvId columns[4];
1153 for (int i = 0; i < dstType.columns(); i++) {
1154 if (i < srcType.columns()) {
1155 // we're still inside the src matrix, copy the column
1156 SpvId srcColumn = this->nextId();
1157 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
1158 SpvId dstColumn;
1159 if (srcType.rows() == dstType.rows()) {
1160 // columns are equal size, don't need to do anything
1161 dstColumn = srcColumn;
1162 }
1163 else if (dstType.rows() > srcType.rows()) {
1164 // dst column is bigger, need to zero-pad it
1165 dstColumn = this->nextId();
1166 int delta = dstType.rows() - srcType.rows();
1167 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1168 this->writeWord(dstColumnType, out);
1169 this->writeWord(dstColumn, out);
1170 this->writeWord(srcColumn, out);
1171 for (int i = 0; i < delta; ++i) {
1172 this->writeWord(zeroId, out);
1173 }
1174 }
1175 else {
1176 // dst column is smaller, need to swizzle the src column
1177 dstColumn = this->nextId();
1178 int count = dstType.rows();
1179 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1180 this->writeWord(dstColumnType, out);
1181 this->writeWord(dstColumn, out);
1182 this->writeWord(srcColumn, out);
1183 this->writeWord(srcColumn, out);
1184 for (int i = 0; i < count; i++) {
1185 this->writeWord(i, out);
1186 }
1187 }
1188 columns[i] = dstColumn;
1189 } else {
1190 // we're past the end of the src matrix, need a vector of zeroes
1191 if (!zeroColumn) {
1192 zeroColumn = this->nextId();
1193 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1194 this->writeWord(dstColumnType, out);
1195 this->writeWord(zeroColumn, out);
1196 for (int i = 0; i < dstType.rows(); ++i) {
1197 this->writeWord(zeroId, out);
1198 }
1199 }
1200 columns[i] = zeroColumn;
1201 }
1202 }
1203 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1204 this->writeWord(this->getType(dstType), out);
1205 this->writeWord(id, out);
1206 for (int i = 0; i < dstType.columns(); i++) {
1207 this->writeWord(columns[i], out);
1208 }
Ethan Nicholas84645e32017-02-09 13:57:14 -05001209}
1210
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001211SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001212 SkASSERT(c.fType.kind() == Type::kMatrix_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001213 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1214 // an instruction
1215 std::vector<SpvId> arguments;
1216 for (size_t i = 0; i < c.fArguments.size(); i++) {
1217 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1218 }
1219 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001220 int rows = c.fType.rows();
1221 int columns = c.fType.columns();
Ethan Nicholas84645e32017-02-09 13:57:14 -05001222 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1223 this->writeUniformScaleMatrix(result, arguments[0], c.fType, out);
1224 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kMatrix_Kind) {
1225 this->writeMatrixCopy(result, arguments[0], c.fArguments[0]->fType, c.fType, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001226 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kVector_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001227 SkASSERT(c.fType.rows() == 2 && c.fType.columns() == 2);
1228 SkASSERT(c.fArguments[0]->fType.columns() == 4);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001229 SpvId componentType = this->getType(c.fType.componentType());
1230 SpvId v[4];
1231 for (int i = 0; i < 4; ++i) {
1232 v[i] = this->nextId();
1233 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i, out);
1234 }
1235 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, 2, 1));
1236 SpvId column1 = this->nextId();
1237 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1238 SpvId column2 = this->nextId();
1239 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
1240 this->writeInstruction(SpvOpCompositeConstruct, this->getType(c.fType), result, column1,
1241 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001242 } else {
1243 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001244 // ids of vectors and scalars we have written to the current column so far
1245 std::vector<SpvId> currentColumn;
1246 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001247 int currentCount = 0;
1248 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001249 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind &&
1250 c.fArguments[i]->fType.columns() == c.fType.rows()) {
1251 // this is a complete column by itself
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001252 SkASSERT(currentCount == 0);
ethannicholasb3058bd2016-07-01 08:22:01 -07001253 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001254 } else {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001255 if (c.fArguments[i]->fType.columns() == 1) {
1256 currentColumn.push_back(arguments[i]);
1257 } else {
1258 SpvId componentType = this->getType(c.fArguments[i]->fType.componentType());
Ethan Nicholas811b9442018-05-11 13:16:03 -04001259 for (int j = 0; j < c.fArguments[i]->fType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001260 SpvId swizzle = this->nextId();
1261 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1262 arguments[i], j, out);
1263 currentColumn.push_back(swizzle);
1264 }
1265 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001266 currentCount += c.fArguments[i]->fType.columns();
1267 if (currentCount == rows) {
1268 currentCount = 0;
1269 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn.size(), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001270 this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows,
1271 1)),
ethannicholasb3058bd2016-07-01 08:22:01 -07001272 out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001273 SpvId columnId = this->nextId();
1274 this->writeWord(columnId, out);
1275 columnIds.push_back(columnId);
1276 for (SpvId id : currentColumn) {
1277 this->writeWord(id, out);
1278 }
1279 currentColumn.clear();
ethannicholasb3058bd2016-07-01 08:22:01 -07001280 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001281 SkASSERT(currentCount < rows);
ethannicholasb3058bd2016-07-01 08:22:01 -07001282 }
1283 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001284 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001285 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001286 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001287 this->writeWord(result, out);
1288 for (SpvId id : columnIds) {
1289 this->writeWord(id, out);
1290 }
1291 }
1292 return result;
1293}
1294
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001295SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001296 SkASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001297 if (c.isConstant()) {
1298 return this->writeConstantVector(c);
1299 }
1300 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1301 // an instruction
1302 std::vector<SpvId> arguments;
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001303 for (size_t i = 0; i < c.fArguments.size(); i++) {
1304 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
1305 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1306 // extract the components and convert them in that case manually. On top of that,
1307 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1308 // doesn't handle vector arguments at all, so we always extract vector components and
1309 // pass them into OpCreateComposite individually.
1310 SpvId vec = this->writeExpression(*c.fArguments[i], out);
1311 SpvOp_ op = SpvOpUndef;
1312 const Type& src = c.fArguments[i]->fType.componentType();
1313 const Type& dst = c.fType.componentType();
1314 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1315 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1316 if (c.fArguments.size() == 1) {
1317 return vec;
1318 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001319 } else if (src == *fContext.fInt_Type ||
1320 src == *fContext.fShort_Type ||
1321 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001322 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001323 } else if (src == *fContext.fUInt_Type ||
1324 src == *fContext.fUShort_Type ||
1325 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001326 op = SpvOpConvertUToF;
1327 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001328 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001329 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001330 } else if (dst == *fContext.fInt_Type ||
1331 dst == *fContext.fShort_Type ||
1332 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001333 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1334 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001335 } else if (src == *fContext.fInt_Type ||
1336 src == *fContext.fShort_Type ||
1337 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001338 if (c.fArguments.size() == 1) {
1339 return vec;
1340 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001341 } else if (src == *fContext.fUInt_Type ||
1342 src == *fContext.fUShort_Type ||
1343 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001344 op = SpvOpBitcast;
1345 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001346 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001347 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001348 } else if (dst == *fContext.fUInt_Type ||
1349 dst == *fContext.fUShort_Type ||
1350 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001351 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1352 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001353 } else if (src == *fContext.fInt_Type ||
1354 src == *fContext.fShort_Type ||
1355 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001356 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001357 } else if (src == *fContext.fUInt_Type ||
1358 src == *fContext.fUShort_Type ||
1359 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001360 if (c.fArguments.size() == 1) {
1361 return vec;
1362 }
1363 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001364 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001365 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001366 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001367 for (int j = 0; j < c.fArguments[i]->fType.columns(); j++) {
1368 SpvId swizzle = this->nextId();
1369 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1370 out);
1371 if (op != SpvOpUndef) {
1372 SpvId cast = this->nextId();
1373 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1374 arguments.push_back(cast);
1375 } else {
1376 arguments.push_back(swizzle);
1377 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001378 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001379 } else {
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001380 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1381 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001382 }
1383 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001384 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1385 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1386 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001387 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001388 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001389 this->writeWord(arguments[0], out);
1390 }
1391 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001392 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001393 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001394 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001395 this->writeWord(result, out);
1396 for (SpvId id : arguments) {
1397 this->writeWord(id, out);
1398 }
1399 }
1400 return result;
1401}
1402
Ethan Nicholasbd553222017-07-18 15:54:59 -04001403SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001404 SkASSERT(c.fType.kind() == Type::kArray_Kind);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001405 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1406 // an instruction
1407 std::vector<SpvId> arguments;
1408 for (size_t i = 0; i < c.fArguments.size(); i++) {
1409 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1410 }
1411 SpvId result = this->nextId();
1412 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
1413 this->writeWord(this->getType(c.fType), out);
1414 this->writeWord(result, out);
1415 for (SpvId id : arguments) {
1416 this->writeWord(id, out);
1417 }
1418 return result;
1419}
1420
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001421SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001422 if (c.fArguments.size() == 1 &&
1423 this->getActualType(c.fType) == this->getActualType(c.fArguments[0]->fType)) {
1424 return this->writeExpression(*c.fArguments[0], out);
1425 }
1426 if (c.fType == *fContext.fFloat_Type || c.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001427 return this->writeFloatConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001428 } else if (c.fType == *fContext.fInt_Type ||
1429 c.fType == *fContext.fShort_Type ||
1430 c.fType == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001431 return this->writeIntConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001432 } else if (c.fType == *fContext.fUInt_Type ||
1433 c.fType == *fContext.fUShort_Type ||
1434 c.fType == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001435 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001436 }
ethannicholasd598f792016-07-25 10:08:54 -07001437 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001438 case Type::kVector_Kind:
1439 return this->writeVectorConstructor(c, out);
1440 case Type::kMatrix_Kind:
1441 return this->writeMatrixConstructor(c, out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001442 case Type::kArray_Kind:
1443 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001444 default:
1445 ABORT("unsupported constructor: %s", c.description().c_str());
1446 }
1447}
1448
1449SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1450 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001451 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001452 return SpvStorageClassInput;
1453 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001454 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001455 return SpvStorageClassOutput;
1456 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001457 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001458 return SpvStorageClassPushConstant;
1459 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001460 return SpvStorageClassUniform;
1461 } else {
1462 return SpvStorageClassFunction;
1463 }
1464}
1465
ethannicholasf789b382016-08-03 12:43:36 -07001466SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001467 switch (expr.fKind) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001468 case Expression::kVariableReference_Kind: {
1469 const Variable& var = ((VariableReference&) expr).fVariable;
1470 if (var.fStorage != Variable::kGlobal_Storage) {
1471 return SpvStorageClassFunction;
1472 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001473 SpvStorageClass_ result = get_storage_class(var.fModifiers);
1474 if (result == SpvStorageClassFunction) {
1475 result = SpvStorageClassPrivate;
1476 }
1477 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001478 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001479 case Expression::kFieldAccess_Kind:
1480 return get_storage_class(*((FieldAccess&) expr).fBase);
1481 case Expression::kIndex_Kind:
1482 return get_storage_class(*((IndexExpression&) expr).fBase);
1483 default:
1484 return SpvStorageClassFunction;
1485 }
1486}
1487
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001488std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001489 std::vector<SpvId> chain;
1490 switch (expr.fKind) {
1491 case Expression::kIndex_Kind: {
1492 IndexExpression& indexExpr = (IndexExpression&) expr;
1493 chain = this->getAccessChain(*indexExpr.fBase, out);
1494 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1495 break;
1496 }
1497 case Expression::kFieldAccess_Kind: {
1498 FieldAccess& fieldExpr = (FieldAccess&) expr;
1499 chain = this->getAccessChain(*fieldExpr.fBase, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001500 IntLiteral index(fContext, -1, fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001501 chain.push_back(this->writeIntLiteral(index));
1502 break;
1503 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001504 default: {
1505 SpvId id = this->getLValue(expr, out)->getPointer();
1506 SkASSERT(id != 0);
1507 chain.push_back(id);
1508 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001509 }
1510 return chain;
1511}
1512
1513class PointerLValue : public SPIRVCodeGenerator::LValue {
1514public:
Greg Daniel64773e62016-11-22 09:44:03 -05001515 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type)
ethannicholasb3058bd2016-07-01 08:22:01 -07001516 : fGen(gen)
1517 , fPointer(pointer)
1518 , fType(type) {}
1519
1520 virtual SpvId getPointer() override {
1521 return fPointer;
1522 }
1523
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001524 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001525 SpvId result = fGen.nextId();
1526 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
1527 return result;
1528 }
1529
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001530 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001531 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1532 }
1533
1534private:
1535 SPIRVCodeGenerator& fGen;
1536 const SpvId fPointer;
1537 const SpvId fType;
1538};
1539
1540class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1541public:
Greg Daniel64773e62016-11-22 09:44:03 -05001542 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
ethannicholasb3058bd2016-07-01 08:22:01 -07001543 const Type& baseType, const Type& swizzleType)
1544 : fGen(gen)
1545 , fVecPointer(vecPointer)
1546 , fComponents(components)
1547 , fBaseType(baseType)
1548 , fSwizzleType(swizzleType) {}
1549
1550 virtual SpvId getPointer() override {
1551 return 0;
1552 }
1553
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001554 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001555 SpvId base = fGen.nextId();
1556 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1557 SpvId result = fGen.nextId();
1558 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1559 fGen.writeWord(fGen.getType(fSwizzleType), out);
1560 fGen.writeWord(result, out);
1561 fGen.writeWord(base, out);
1562 fGen.writeWord(base, out);
1563 for (int component : fComponents) {
1564 fGen.writeWord(component, out);
1565 }
1566 return result;
1567 }
1568
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001569 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001570 // use OpVectorShuffle to mix and match the vector components. We effectively create
1571 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001572 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001573 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001574 // float3L = ...;
1575 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001576 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001577 // 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 -07001578 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1579 // (3, 1, 4).
1580 SpvId base = fGen.nextId();
1581 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1582 SpvId shuffle = fGen.nextId();
1583 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1584 fGen.writeWord(fGen.getType(fBaseType), out);
1585 fGen.writeWord(shuffle, out);
1586 fGen.writeWord(base, out);
1587 fGen.writeWord(value, out);
1588 for (int i = 0; i < fBaseType.columns(); i++) {
1589 // current offset into the virtual vector, defaults to pulling the unmodified
1590 // value from the left side
1591 int offset = i;
1592 // check to see if we are writing this component
1593 for (size_t j = 0; j < fComponents.size(); j++) {
1594 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001595 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001596 // the correct component of the right side instead of preserving the
1597 // value from the left
1598 offset = (int) (j + fBaseType.columns());
1599 break;
1600 }
1601 }
1602 fGen.writeWord(offset, out);
1603 }
1604 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1605 }
1606
1607private:
1608 SPIRVCodeGenerator& fGen;
1609 const SpvId fVecPointer;
1610 const std::vector<int>& fComponents;
1611 const Type& fBaseType;
1612 const Type& fSwizzleType;
1613};
1614
Greg Daniel64773e62016-11-22 09:44:03 -05001615std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001616 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001617 switch (expr.fKind) {
1618 case Expression::kVariableReference_Kind: {
Ethan Nicholas5226b772018-05-03 16:20:41 -04001619 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07001620 const Variable& var = ((VariableReference&) expr).fVariable;
Ethan Nicholas5226b772018-05-03 16:20:41 -04001621 if (var.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
1622 type = this->getType(Type("sk_in", Type::kArray_Kind, var.fType.componentType(),
1623 fSkInCount));
1624 } else {
1625 type = this->getType(expr.fType);
1626 }
ethannicholasd598f792016-07-25 10:08:54 -07001627 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001628 SkASSERT(entry != fVariableMap.end());
Ethan Nicholas5226b772018-05-03 16:20:41 -04001629 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(*this,
1630 entry->second,
1631 type));
ethannicholasb3058bd2016-07-01 08:22:01 -07001632 }
1633 case Expression::kIndex_Kind: // fall through
1634 case Expression::kFieldAccess_Kind: {
1635 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1636 SpvId member = this->nextId();
1637 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001638 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001639 this->writeWord(member, out);
1640 for (SpvId idx : chain) {
1641 this->writeWord(idx, out);
1642 }
1643 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -04001644 *this,
1645 member,
1646 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001647 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001648 case Expression::kSwizzle_Kind: {
1649 Swizzle& swizzle = (Swizzle&) expr;
1650 size_t count = swizzle.fComponents.size();
1651 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001652 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001653 if (count == 1) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001654 IntLiteral index(fContext, -1, swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001655 SpvId member = this->nextId();
1656 this->writeInstruction(SpvOpAccessChain,
Greg Daniel64773e62016-11-22 09:44:03 -05001657 this->getPointerType(swizzle.fType,
1658 get_storage_class(*swizzle.fBase)),
1659 member,
1660 base,
1661 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001662 out);
1663 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1664 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001665 member,
ethannicholasd598f792016-07-25 10:08:54 -07001666 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001667 } else {
1668 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
Greg Daniel64773e62016-11-22 09:44:03 -05001669 *this,
1670 base,
1671 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001672 swizzle.fBase->fType,
1673 expr.fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07001674 }
1675 }
Ethan Nicholasa583b812018-01-18 13:32:11 -05001676 case Expression::kTernary_Kind: {
1677 TernaryExpression& t = (TernaryExpression&) expr;
1678 SpvId test = this->writeExpression(*t.fTest, out);
1679 SpvId end = this->nextId();
1680 SpvId ifTrueLabel = this->nextId();
1681 SpvId ifFalseLabel = this->nextId();
1682 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1683 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1684 this->writeLabel(ifTrueLabel, out);
1685 SpvId ifTrue = this->getLValue(*t.fIfTrue, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001686 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001687 this->writeInstruction(SpvOpBranch, end, out);
1688 ifTrueLabel = fCurrentBlock;
1689 SpvId ifFalse = this->getLValue(*t.fIfFalse, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001690 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001691 ifFalseLabel = fCurrentBlock;
1692 this->writeInstruction(SpvOpBranch, end, out);
1693 SpvId result = this->nextId();
1694 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1695 ifTrueLabel, ifFalse, ifFalseLabel, out);
1696 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1697 *this,
1698 result,
1699 this->getType(expr.fType)));
1700 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001701 default:
1702 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001703 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001704 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1705 // caught by IRGenerator
1706 SpvId result = this->nextId();
1707 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001708 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1709 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001710 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1711 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1712 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001713 result,
ethannicholasd598f792016-07-25 10:08:54 -07001714 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001715 }
1716}
1717
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001718SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001719 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001720 auto entry = fVariableMap.find(&ref.fVariable);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001721 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001722 SpvId var = entry->second;
ethannicholasd598f792016-07-25 10:08:54 -07001723 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001724 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
1725 fProgram.fSettings.fFlipY) {
1726 // need to remap to a top-left coordinate system
Greg Daniele6ab9982018-08-22 13:56:32 +00001727 if (fRTHeightStructId == (SpvId) -1) {
1728 // height variable hasn't been written yet
1729 std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors));
1730 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
1731 std::vector<Type::Field> fields;
1732 fields.emplace_back(Modifiers(), SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1733 StringFragment name("sksl_synthetic_uniforms");
1734 Type intfStruct(-1, name, fields);
1735 Layout layout(0, -1, -1, 1, -1, -1, -1, -1, Layout::Format::kUnspecified,
1736 Layout::kUnspecified_Primitive, -1, -1, "", Layout::kNo_Key,
Ethan Nicholas78aceb22018-08-31 16:13:58 -04001737 Layout::CType::kDefault);
Greg Daniele6ab9982018-08-22 13:56:32 +00001738 Variable* intfVar = new Variable(-1,
1739 Modifiers(layout, Modifiers::kUniform_Flag),
1740 name,
1741 intfStruct,
1742 Variable::kGlobal_Storage);
1743 fSynthetics.takeOwnership(intfVar);
1744 InterfaceBlock intf(-1, intfVar, name, String(""),
1745 std::vector<std::unique_ptr<Expression>>(), st);
1746 fRTHeightStructId = this->writeInterfaceBlock(intf);
1747 fRTHeightFieldIndex = 0;
1748 }
1749 SkASSERT(fRTHeightFieldIndex != (SpvId) -1);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001750 // write float4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, gl_FragCoord.w)
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001751 SpvId xId = this->nextId();
1752 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1753 result, 0, out);
Greg Daniele6ab9982018-08-22 13:56:32 +00001754 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1755 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1756 SpvId heightPtr = this->nextId();
1757 this->writeOpCode(SpvOpAccessChain, 5, out);
1758 this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out);
1759 this->writeWord(heightPtr, out);
1760 this->writeWord(fRTHeightStructId, out);
1761 this->writeWord(fieldIndexId, out);
1762 SpvId heightRead = this->nextId();
1763 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1764 heightPtr, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001765 SpvId rawYId = this->nextId();
1766 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1767 result, 1, out);
1768 SpvId flippedYId = this->nextId();
1769 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
Greg Daniele6ab9982018-08-22 13:56:32 +00001770 heightRead, rawYId, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001771 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001772 SpvId zeroId = writeFloatLiteral(zero);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001773 FloatLiteral one(fContext, -1, 1.0);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001774 SpvId wId = this->nextId();
1775 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), wId,
1776 result, 3, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001777 SpvId flipped = this->nextId();
1778 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001779 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001780 this->writeWord(flipped, out);
1781 this->writeWord(xId, out);
1782 this->writeWord(flippedYId, out);
1783 this->writeWord(zeroId, out);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001784 this->writeWord(wId, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001785 return flipped;
1786 }
Chris Daltonb91c4662018-08-01 10:46:22 -06001787 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
1788 !fProgram.fSettings.fFlipY) {
1789 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1790 // the default convention of "counter-clockwise face is front".
1791 SpvId inverse = this->nextId();
1792 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1793 result, out);
1794 return inverse;
1795 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001796 return result;
1797}
1798
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001799SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001800 if (expr.fBase->fType.kind() == Type::Kind::kVector_Kind) {
1801 SpvId base = this->writeExpression(*expr.fBase, out);
1802 SpvId index = this->writeExpression(*expr.fIndex, out);
1803 SpvId result = this->nextId();
1804 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.fType), result, base,
1805 index, out);
1806 return result;
1807 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001808 return getLValue(expr, out)->load(out);
1809}
1810
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001811SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001812 return getLValue(f, out)->load(out);
1813}
1814
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001815SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001816 SpvId base = this->writeExpression(*swizzle.fBase, out);
1817 SpvId result = this->nextId();
1818 size_t count = swizzle.fComponents.size();
1819 if (count == 1) {
Greg Daniel64773e62016-11-22 09:44:03 -05001820 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
1821 swizzle.fComponents[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001822 } else {
1823 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
ethannicholasd598f792016-07-25 10:08:54 -07001824 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001825 this->writeWord(result, out);
1826 this->writeWord(base, out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001827 SpvId other;
1828 int last = swizzle.fComponents.back();
1829 if (last < 0) {
1830 if (!fConstantZeroOneVector) {
1831 FloatLiteral zero(fContext, -1, 0);
1832 SpvId zeroId = this->writeFloatLiteral(zero);
1833 FloatLiteral one(fContext, -1, 1);
Ethan Nicholas0b2c0542019-02-25 14:29:11 -05001834 SpvId oneId = this->writeFloatLiteral(one);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001835 SpvId type = this->getType(*fContext.fFloat2_Type);
1836 fConstantZeroOneVector = this->nextId();
1837 this->writeOpCode(SpvOpConstantComposite, 5, fConstantBuffer);
1838 this->writeWord(type, fConstantBuffer);
1839 this->writeWord(fConstantZeroOneVector, fConstantBuffer);
1840 this->writeWord(zeroId, fConstantBuffer);
1841 this->writeWord(oneId, fConstantBuffer);
1842 }
1843 other = fConstantZeroOneVector;
1844 } else {
1845 other = base;
1846 }
1847 this->writeWord(other, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001848 for (int component : swizzle.fComponents) {
Ethan Nicholasac285b12019-02-12 16:05:18 -05001849 if (component == SKSL_SWIZZLE_0) {
Ethan Nicholas0b2c0542019-02-25 14:29:11 -05001850 this->writeWord(swizzle.fBase->fType.columns(), out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001851 } else if (component == SKSL_SWIZZLE_1) {
Ethan Nicholas0b2c0542019-02-25 14:29:11 -05001852 this->writeWord(swizzle.fBase->fType.columns() + 1, out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001853 } else {
1854 this->writeWord(component, out);
1855 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001856 }
1857 }
1858 return result;
1859}
1860
Greg Daniel64773e62016-11-22 09:44:03 -05001861SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1862 const Type& operandType, SpvId lhs,
1863 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001864 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001865 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001866 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001867 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001868 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001869 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001870 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001871 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001872 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001873 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
1874 } else {
1875 ABORT("invalid operandType: %s", operandType.description().c_str());
1876 }
1877 return result;
1878}
1879
1880bool is_assignment(Token::Kind op) {
1881 switch (op) {
1882 case Token::EQ: // fall through
1883 case Token::PLUSEQ: // fall through
1884 case Token::MINUSEQ: // fall through
1885 case Token::STAREQ: // fall through
1886 case Token::SLASHEQ: // fall through
1887 case Token::PERCENTEQ: // fall through
1888 case Token::SHLEQ: // fall through
1889 case Token::SHREQ: // fall through
1890 case Token::BITWISEOREQ: // fall through
1891 case Token::BITWISEXOREQ: // fall through
1892 case Token::BITWISEANDEQ: // fall through
1893 case Token::LOGICALOREQ: // fall through
1894 case Token::LOGICALXOREQ: // fall through
1895 case Token::LOGICALANDEQ:
1896 return true;
1897 default:
1898 return false;
1899 }
1900}
1901
Ethan Nicholas48e24052018-03-14 13:51:39 -04001902SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
1903 OutputStream& out) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05001904 if (operandType.kind() == Type::kVector_Kind) {
1905 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001906 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05001907 return result;
1908 }
1909 return id;
1910}
1911
Ethan Nicholas68990be2017-07-13 09:36:52 -04001912SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
1913 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04001914 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04001915 OutputStream& out) {
1916 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001917 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0df21132018-07-10 09:37:51 -04001918 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
1919 operandType.rows(),
1920 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04001921 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04001922 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04001923 1));
1924 SpvId boolType = this->getType(*fContext.fBool_Type);
1925 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04001926 for (int i = 0; i < operandType.columns(); i++) {
1927 SpvId columnL = this->nextId();
1928 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
1929 SpvId columnR = this->nextId();
1930 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04001931 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04001932 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
1933 SpvId merge = this->nextId();
1934 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04001935 if (result != 0) {
1936 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04001937 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04001938 result = next;
1939 }
1940 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04001941 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04001942 }
1943 }
1944 return result;
1945}
1946
Ethan Nicholas0df21132018-07-10 09:37:51 -04001947SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
1948 SpvId rhs, SpvOp_ floatOperator,
1949 SpvOp_ intOperator,
1950 OutputStream& out) {
1951 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
1952 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
1953 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
1954 operandType.rows(),
1955 1));
1956 SpvId columns[4];
1957 for (int i = 0; i < operandType.columns(); i++) {
1958 SpvId columnL = this->nextId();
1959 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
1960 SpvId columnR = this->nextId();
1961 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
1962 columns[i] = this->nextId();
1963 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
1964 }
1965 SpvId result = this->nextId();
1966 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
1967 this->writeWord(this->getType(operandType), out);
1968 this->writeWord(result, out);
1969 for (int i = 0; i < operandType.columns(); i++) {
1970 this->writeWord(columns[i], out);
1971 }
1972 return result;
1973}
1974
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001975SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001976 // handle cases where we don't necessarily evaluate both LHS and RHS
1977 switch (b.fOperator) {
1978 case Token::EQ: {
1979 SpvId rhs = this->writeExpression(*b.fRight, out);
1980 this->getLValue(*b.fLeft, out)->store(rhs, out);
1981 return rhs;
1982 }
1983 case Token::LOGICALAND:
1984 return this->writeLogicalAnd(b, out);
1985 case Token::LOGICALOR:
1986 return this->writeLogicalOr(b, out);
1987 default:
1988 break;
1989 }
1990
1991 // "normal" operators
ethannicholasd598f792016-07-25 10:08:54 -07001992 const Type& resultType = b.fType;
ethannicholasb3058bd2016-07-01 08:22:01 -07001993 std::unique_ptr<LValue> lvalue;
1994 SpvId lhs;
1995 if (is_assignment(b.fOperator)) {
1996 lvalue = this->getLValue(*b.fLeft, out);
1997 lhs = lvalue->load(out);
1998 } else {
1999 lvalue = nullptr;
2000 lhs = this->writeExpression(*b.fLeft, out);
2001 }
2002 SpvId rhs = this->writeExpression(*b.fRight, out);
Ethan Nicholas6feb6912017-06-30 12:23:36 -04002003 if (b.fOperator == Token::COMMA) {
2004 return rhs;
2005 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002006 Type tmp("<invalid>");
Ethan Nicholas48e24052018-03-14 13:51:39 -04002007 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002008 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002009 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2010 // handling in SPIR-V
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002011 if (this->getActualType(b.fLeft->fType) != this->getActualType(b.fRight->fType)) {
Greg Daniel64773e62016-11-22 09:44:03 -05002012 if (b.fLeft->fType.kind() == Type::kVector_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002013 b.fRight->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002014 // promote number to vector
2015 SpvId vec = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04002016 const Type& vecType = b.fLeft->fType;
2017 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2018 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002019 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002020 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002021 this->writeWord(rhs, out);
2022 }
2023 rhs = vec;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002024 operandType = &b.fLeft->fType;
Greg Daniel64773e62016-11-22 09:44:03 -05002025 } else if (b.fRight->fType.kind() == Type::kVector_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002026 b.fLeft->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002027 // promote number to vector
2028 SpvId vec = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04002029 const Type& vecType = b.fRight->fType;
2030 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2031 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002032 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002033 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002034 this->writeWord(lhs, out);
2035 }
2036 lhs = vec;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002037 SkASSERT(!lvalue);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002038 operandType = &b.fRight->fType;
ethannicholasd598f792016-07-25 10:08:54 -07002039 } else if (b.fLeft->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002040 SpvOp_ op;
ethannicholasd598f792016-07-25 10:08:54 -07002041 if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002042 op = SpvOpMatrixTimesMatrix;
ethannicholasd598f792016-07-25 10:08:54 -07002043 } else if (b.fRight->fType.kind() == Type::kVector_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002044 op = SpvOpMatrixTimesVector;
2045 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002046 SkASSERT(b.fRight->fType.kind() == Type::kScalar_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07002047 op = SpvOpMatrixTimesScalar;
2048 }
2049 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002050 this->writeInstruction(op, this->getType(b.fType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002051 if (b.fOperator == Token::STAREQ) {
2052 lvalue->store(result, out);
2053 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002054 SkASSERT(b.fOperator == Token::STAR);
ethannicholasb3058bd2016-07-01 08:22:01 -07002055 }
2056 return result;
ethannicholasd598f792016-07-25 10:08:54 -07002057 } else if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002058 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002059 if (b.fLeft->fType.kind() == Type::kVector_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05002060 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(b.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002061 lhs, rhs, out);
2062 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002063 SkASSERT(b.fLeft->fType.kind() == Type::kScalar_Kind);
Greg Daniel64773e62016-11-22 09:44:03 -05002064 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(b.fType), result, rhs,
ethannicholasb3058bd2016-07-01 08:22:01 -07002065 lhs, out);
2066 }
2067 if (b.fOperator == Token::STAREQ) {
2068 lvalue->store(result, out);
2069 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002070 SkASSERT(b.fOperator == Token::STAR);
ethannicholasb3058bd2016-07-01 08:22:01 -07002071 }
2072 return result;
2073 } else {
Ethan Nicholase1f55022019-02-05 17:17:40 -05002074 ABORT("unsupported binary expression: %s (%s, %s)", b.description().c_str(),
2075 b.fLeft->fType.description().c_str(), b.fRight->fType.description().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002076 }
2077 } else {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002078 tmp = this->getActualType(b.fLeft->fType);
2079 operandType = &tmp;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002080 SkASSERT(*operandType == this->getActualType(b.fRight->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002081 }
2082 switch (b.fOperator) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002083 case Token::EQEQ: {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002084 if (operandType->kind() == Type::kMatrix_Kind) {
2085 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002086 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002087 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002088 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002089 const Type* tmpType;
2090 if (operandType->kind() == Type::kVector_Kind) {
2091 tmpType = &fContext.fBool_Type->toCompound(fContext,
2092 operandType->columns(),
2093 operandType->rows());
2094 } else {
2095 tmpType = &resultType;
2096 }
2097 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002098 SpvOpFOrdEqual, SpvOpIEqual,
2099 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002100 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002101 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002102 case Token::NEQ:
Ethan Nicholas68990be2017-07-13 09:36:52 -04002103 if (operandType->kind() == Type::kMatrix_Kind) {
2104 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002105 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002106 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002107 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002108 const Type* tmpType;
2109 if (operandType->kind() == Type::kVector_Kind) {
2110 tmpType = &fContext.fBool_Type->toCompound(fContext,
2111 operandType->columns(),
2112 operandType->rows());
2113 } else {
2114 tmpType = &resultType;
2115 }
2116 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002117 SpvOpFOrdNotEqual, SpvOpINotEqual,
2118 SpvOpINotEqual, SpvOpLogicalNotEqual,
2119 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002120 *operandType, SpvOpAny, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002121 case Token::GT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002122 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002123 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2124 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002125 SpvOpUGreaterThan, SpvOpUndef, out);
2126 case Token::LT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002127 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002128 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002129 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
2130 case Token::GTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002131 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002132 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2133 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002134 SpvOpUGreaterThanEqual, SpvOpUndef, out);
2135 case Token::LTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002136 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002137 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2138 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002139 SpvOpULessThanEqual, SpvOpUndef, out);
2140 case Token::PLUS:
Ethan Nicholas0df21132018-07-10 09:37:51 -04002141 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2142 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2143 SkASSERT(b.fLeft->fType == b.fRight->fType);
2144 return this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2145 SpvOpFAdd, SpvOpIAdd, out);
2146 }
Greg Daniel64773e62016-11-22 09:44:03 -05002147 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002148 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2149 case Token::MINUS:
Ethan Nicholas0df21132018-07-10 09:37:51 -04002150 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2151 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2152 SkASSERT(b.fLeft->fType == b.fRight->fType);
2153 return this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2154 SpvOpFSub, SpvOpISub, out);
2155 }
Greg Daniel64773e62016-11-22 09:44:03 -05002156 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002157 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2158 case Token::STAR:
Greg Daniel64773e62016-11-22 09:44:03 -05002159 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002160 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002161 // matrix multiply
2162 SpvId result = this->nextId();
2163 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2164 lhs, rhs, out);
2165 return result;
2166 }
Greg Daniel64773e62016-11-22 09:44:03 -05002167 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002168 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2169 case Token::SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002170 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002171 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002172 case Token::PERCENT:
2173 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2174 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002175 case Token::SHL:
2176 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2177 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2178 SpvOpUndef, out);
2179 case Token::SHR:
2180 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2181 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2182 SpvOpUndef, out);
2183 case Token::BITWISEAND:
2184 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2185 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
2186 case Token::BITWISEOR:
2187 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2188 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
2189 case Token::BITWISEXOR:
2190 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2191 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002192 case Token::PLUSEQ: {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002193 SpvId result;
2194 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2195 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2196 SkASSERT(b.fLeft->fType == b.fRight->fType);
2197 result = this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2198 SpvOpFAdd, SpvOpIAdd, out);
2199 }
2200 else {
2201 result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002202 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002203 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002204 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002205 lvalue->store(result, out);
2206 return result;
2207 }
2208 case Token::MINUSEQ: {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002209 SpvId result;
2210 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2211 b.fRight->fType.kind() == Type::kMatrix_Kind) {
2212 SkASSERT(b.fLeft->fType == b.fRight->fType);
2213 result = this->writeComponentwiseMatrixBinary(b.fLeft->fType, lhs, rhs,
2214 SpvOpFSub, SpvOpISub, out);
2215 }
2216 else {
2217 result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002218 SpvOpISub, SpvOpISub, SpvOpUndef, out);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002219 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002220 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002221 lvalue->store(result, out);
2222 return result;
2223 }
2224 case Token::STAREQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002225 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002226 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002227 // matrix multiply
2228 SpvId result = this->nextId();
2229 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2230 lhs, rhs, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002231 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002232 lvalue->store(result, out);
2233 return result;
2234 }
Greg Daniel64773e62016-11-22 09:44:03 -05002235 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002236 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002237 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002238 lvalue->store(result, out);
2239 return result;
2240 }
2241 case Token::SLASHEQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002242 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002243 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002244 SkASSERT(lvalue);
ethannicholasb3058bd2016-07-01 08:22:01 -07002245 lvalue->store(result, out);
2246 return result;
2247 }
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002248 case Token::PERCENTEQ: {
2249 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2250 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002251 SkASSERT(lvalue);
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002252 lvalue->store(result, out);
2253 return result;
2254 }
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002255 case Token::SHLEQ: {
2256 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2257 SpvOpUndef, SpvOpShiftLeftLogical,
2258 SpvOpShiftLeftLogical, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002259 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002260 lvalue->store(result, out);
2261 return result;
2262 }
2263 case Token::SHREQ: {
2264 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2265 SpvOpUndef, SpvOpShiftRightArithmetic,
2266 SpvOpShiftRightLogical, SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002267 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002268 lvalue->store(result, out);
2269 return result;
2270 }
2271 case Token::BITWISEANDEQ: {
2272 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2273 SpvOpUndef, SpvOpBitwiseAnd, SpvOpBitwiseAnd,
2274 SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002275 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002276 lvalue->store(result, out);
2277 return result;
2278 }
2279 case Token::BITWISEOREQ: {
2280 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2281 SpvOpUndef, SpvOpBitwiseOr, SpvOpBitwiseOr,
2282 SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002283 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002284 lvalue->store(result, out);
2285 return result;
2286 }
2287 case Token::BITWISEXOREQ: {
2288 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2289 SpvOpUndef, SpvOpBitwiseXor, SpvOpBitwiseXor,
2290 SpvOpUndef, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002291 SkASSERT(lvalue);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002292 lvalue->store(result, out);
2293 return result;
2294 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002295 default:
ethannicholasb3058bd2016-07-01 08:22:01 -07002296 ABORT("unsupported binary expression: %s", b.description().c_str());
2297 }
2298}
2299
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002300SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002301 SkASSERT(a.fOperator == Token::LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002302 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002303 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2304 SpvId lhs = this->writeExpression(*a.fLeft, out);
2305 SpvId rhsLabel = this->nextId();
2306 SpvId end = this->nextId();
2307 SpvId lhsBlock = fCurrentBlock;
2308 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2309 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2310 this->writeLabel(rhsLabel, out);
2311 SpvId rhs = this->writeExpression(*a.fRight, out);
2312 SpvId rhsBlock = fCurrentBlock;
2313 this->writeInstruction(SpvOpBranch, end, out);
2314 this->writeLabel(end, out);
2315 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002316 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002317 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002318 return result;
2319}
2320
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002321SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002322 SkASSERT(o.fOperator == Token::LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002323 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002324 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2325 SpvId lhs = this->writeExpression(*o.fLeft, out);
2326 SpvId rhsLabel = this->nextId();
2327 SpvId end = this->nextId();
2328 SpvId lhsBlock = fCurrentBlock;
2329 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2330 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2331 this->writeLabel(rhsLabel, out);
2332 SpvId rhs = this->writeExpression(*o.fRight, out);
2333 SpvId rhsBlock = fCurrentBlock;
2334 this->writeInstruction(SpvOpBranch, end, out);
2335 this->writeLabel(end, out);
2336 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002337 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002338 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002339 return result;
2340}
2341
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002342SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002343 SpvId test = this->writeExpression(*t.fTest, out);
Ethan Nicholas0f21c232018-07-23 09:25:40 -04002344 if (t.fIfTrue->fType.columns() == 1 && t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002345 // both true and false are constants, can just use OpSelect
2346 SpvId result = this->nextId();
2347 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2348 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
Greg Daniel64773e62016-11-22 09:44:03 -05002349 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002350 out);
2351 return result;
2352 }
Greg Daniel64773e62016-11-22 09:44:03 -05002353 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002354 // Adreno. Switched to storing the result in a temp variable as glslang does.
2355 SpvId var = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002356 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002357 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002358 SpvId trueLabel = this->nextId();
2359 SpvId falseLabel = this->nextId();
2360 SpvId end = this->nextId();
2361 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2362 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2363 this->writeLabel(trueLabel, out);
2364 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2365 this->writeInstruction(SpvOpBranch, end, out);
2366 this->writeLabel(falseLabel, out);
2367 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2368 this->writeInstruction(SpvOpBranch, end, out);
2369 this->writeLabel(end, out);
2370 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002371 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002372 return result;
2373}
2374
ethannicholasd598f792016-07-25 10:08:54 -07002375std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
Ethan Nicholas024301a2017-11-10 13:49:18 -05002376 if (type.isInteger()) {
Ethan Nicholas00543112018-07-31 09:44:36 -04002377 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002378 }
Ethan Nicholas024301a2017-11-10 13:49:18 -05002379 else if (type.isFloat()) {
Ethan Nicholas00543112018-07-31 09:44:36 -04002380 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002381 } else {
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002382 ABORT("math is unsupported on type '%s'", type.name().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002383 }
2384}
2385
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002386SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002387 if (p.fOperator == Token::MINUS) {
2388 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002389 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002390 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002391 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002392 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002393 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002394 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2395 } else {
2396 ABORT("unsupported prefix expression %s", p.description().c_str());
Brian Salomon23356442018-11-30 15:33:19 -05002397 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002398 return result;
2399 }
2400 switch (p.fOperator) {
2401 case Token::PLUS:
2402 return this->writeExpression(*p.fOperand, out);
2403 case Token::PLUSPLUS: {
2404 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002405 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002406 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2407 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002408 out);
2409 lv->store(result, out);
2410 return result;
2411 }
2412 case Token::MINUSMINUS: {
2413 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002414 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002415 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2416 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002417 out);
2418 lv->store(result, out);
2419 return result;
2420 }
ethannicholas5961bc92016-10-12 06:39:56 -07002421 case Token::LOGICALNOT: {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002422 SkASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002423 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002424 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002425 this->writeExpression(*p.fOperand, out), out);
2426 return result;
2427 }
ethannicholas5961bc92016-10-12 06:39:56 -07002428 case Token::BITWISENOT: {
2429 SpvId result = this->nextId();
2430 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2431 this->writeExpression(*p.fOperand, out), out);
2432 return result;
2433 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002434 default:
2435 ABORT("unsupported prefix expression: %s", p.description().c_str());
2436 }
2437}
2438
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002439SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002440 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2441 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002442 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002443 switch (p.fOperator) {
2444 case Token::PLUSPLUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002445 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002446 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2447 lv->store(temp, out);
2448 return result;
2449 }
2450 case Token::MINUSMINUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002451 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002452 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2453 lv->store(temp, out);
2454 return result;
2455 }
2456 default:
2457 ABORT("unsupported postfix expression %s", p.description().c_str());
2458 }
2459}
2460
ethannicholasf789b382016-08-03 12:43:36 -07002461SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002462 if (b.fValue) {
2463 if (fBoolTrue == 0) {
2464 fBoolTrue = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002465 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002466 fConstantBuffer);
2467 }
2468 return fBoolTrue;
2469 } else {
2470 if (fBoolFalse == 0) {
2471 fBoolFalse = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002472 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002473 fConstantBuffer);
2474 }
2475 return fBoolFalse;
2476 }
2477}
2478
ethannicholasf789b382016-08-03 12:43:36 -07002479SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholasd598f792016-07-25 10:08:54 -07002480 if (i.fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002481 auto entry = fIntConstants.find(i.fValue);
2482 if (entry == fIntConstants.end()) {
2483 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002484 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002485 fConstantBuffer);
2486 fIntConstants[i.fValue] = result;
2487 return result;
2488 }
2489 return entry->second;
2490 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002491 SkASSERT(i.fType == *fContext.fUInt_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002492 auto entry = fUIntConstants.find(i.fValue);
2493 if (entry == fUIntConstants.end()) {
2494 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002495 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002496 fConstantBuffer);
2497 fUIntConstants[i.fValue] = result;
2498 return result;
2499 }
2500 return entry->second;
2501 }
2502}
2503
ethannicholasf789b382016-08-03 12:43:36 -07002504SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholase1f55022019-02-05 17:17:40 -05002505 if (f.fType != *fContext.fDouble_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002506 float value = (float) f.fValue;
2507 auto entry = fFloatConstants.find(value);
2508 if (entry == fFloatConstants.end()) {
2509 SpvId result = this->nextId();
2510 uint32_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002511 SkASSERT(sizeof(bits) == sizeof(value));
ethannicholasb3058bd2016-07-01 08:22:01 -07002512 memcpy(&bits, &value, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002513 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
ethannicholasb3058bd2016-07-01 08:22:01 -07002514 fConstantBuffer);
2515 fFloatConstants[value] = result;
2516 return result;
2517 }
2518 return entry->second;
2519 } else {
ethannicholasb3058bd2016-07-01 08:22:01 -07002520 auto entry = fDoubleConstants.find(f.fValue);
2521 if (entry == fDoubleConstants.end()) {
2522 SpvId result = this->nextId();
2523 uint64_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002524 SkASSERT(sizeof(bits) == sizeof(f.fValue));
ethannicholasb3058bd2016-07-01 08:22:01 -07002525 memcpy(&bits, &f.fValue, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002526 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002527 bits & 0xffffffff, bits >> 32, fConstantBuffer);
2528 fDoubleConstants[f.fValue] = result;
2529 return result;
2530 }
2531 return entry->second;
2532 }
2533}
2534
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002535SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002536 SpvId result = fFunctionMap[&f];
Greg Daniel64773e62016-11-22 09:44:03 -05002537 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002538 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002539 this->writeInstruction(SpvOpName, result, f.fName, fNameBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002540 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002541 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002542 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002543 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002544 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002545 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2546 }
2547 return result;
2548}
2549
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002550SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2551 fVariableBuffer.reset();
ethannicholasb3058bd2016-07-01 08:22:01 -07002552 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2553 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002554 StringStream bodyBuffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04002555 this->writeBlock((Block&) *f.fBody, bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002556 write_stringstream(fVariableBuffer, out);
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002557 if (f.fDeclaration.fName == "main") {
2558 write_stringstream(fGlobalInitializersBuffer, out);
2559 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002560 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002561 if (fCurrentBlock) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002562 if (f.fDeclaration.fReturnType == *fContext.fVoid_Type) {
2563 this->writeInstruction(SpvOpReturn, out);
2564 } else {
2565 this->writeInstruction(SpvOpUnreachable, out);
2566 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002567 }
2568 this->writeInstruction(SpvOpFunctionEnd, out);
2569 return result;
2570}
2571
2572void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2573 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002574 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002575 fDecorationBuffer);
2576 }
2577 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002578 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002579 fDecorationBuffer);
2580 }
2581 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002582 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002583 fDecorationBuffer);
2584 }
2585 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002586 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002587 fDecorationBuffer);
2588 }
Greg Daniel64773e62016-11-22 09:44:03 -05002589 if (layout.fInputAttachmentIndex >= 0) {
2590 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2591 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002592 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002593 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002594 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002595 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002596 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002597 fDecorationBuffer);
2598 }
2599}
2600
2601void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2602 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002603 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002604 layout.fLocation, fDecorationBuffer);
2605 }
2606 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002607 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002608 layout.fBinding, fDecorationBuffer);
2609 }
2610 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002611 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002612 layout.fIndex, fDecorationBuffer);
2613 }
2614 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002615 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002616 layout.fSet, fDecorationBuffer);
2617 }
Greg Daniel64773e62016-11-22 09:44:03 -05002618 if (layout.fInputAttachmentIndex >= 0) {
2619 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2620 layout.fInputAttachmentIndex, fDecorationBuffer);
2621 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002622 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002623 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002624 layout.fBuiltin, fDecorationBuffer);
2625 }
2626}
2627
Ethan Nicholas81d15112018-07-13 12:48:50 -04002628static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2629 switch (m.fLayout.fPrimitive) {
2630 case Layout::kPoints_Primitive:
2631 *outSkInCount = 1;
2632 break;
2633 case Layout::kLines_Primitive:
2634 *outSkInCount = 2;
2635 break;
2636 case Layout::kLinesAdjacency_Primitive:
2637 *outSkInCount = 4;
2638 break;
2639 case Layout::kTriangles_Primitive:
2640 *outSkInCount = 3;
2641 break;
2642 case Layout::kTrianglesAdjacency_Primitive:
2643 *outSkInCount = 6;
2644 break;
2645 default:
2646 return;
2647 }
2648}
2649
ethannicholasf789b382016-08-03 12:43:36 -07002650SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas361941e2017-05-30 15:41:07 -04002651 bool isBuffer = (0 != (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag));
Ethan Nicholas39204fd2017-11-27 13:12:30 -05002652 bool pushConstant = (0 != (intf.fVariable.fModifiers.fLayout.fFlags &
2653 Layout::kPushConstant_Flag));
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002654 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2655 MemoryLayout(MemoryLayout::k430_Standard) :
2656 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002657 SpvId result = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002658 const Type* type = &intf.fVariable.fType;
Greg Daniele6ab9982018-08-22 13:56:32 +00002659 if (fProgram.fInputs.fRTHeight) {
2660 SkASSERT(fRTHeightStructId == (SpvId) -1);
2661 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002662 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002663 fRTHeightStructId = result;
2664 fRTHeightFieldIndex = fields.size();
2665 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002666 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002667 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002668 SpvId typeId;
2669 if (intf.fVariable.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2670 for (const auto& e : fProgram) {
2671 if (e.fKind == ProgramElement::kModifiers_Kind) {
2672 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholas81d15112018-07-13 12:48:50 -04002673 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002674 }
2675 }
2676 typeId = this->getType(Type("sk_in", Type::kArray_Kind, intf.fVariable.fType.componentType(),
2677 fSkInCount), memoryLayout);
2678 } else {
2679 typeId = this->getType(*type, memoryLayout);
2680 }
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002681 if (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag) {
2682 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002683 } else if (intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
2684 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002685 }
ethannicholasd598f792016-07-25 10:08:54 -07002686 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002687 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002688 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002689 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002690 Layout layout = intf.fVariable.fModifiers.fLayout;
2691 if (intf.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
2692 layout.fSet = 0;
2693 }
2694 this->writeLayout(layout, result);
ethannicholasd598f792016-07-25 10:08:54 -07002695 fVariableMap[&intf.fVariable] = result;
Greg Daniele6ab9982018-08-22 13:56:32 +00002696 if (fProgram.fInputs.fRTHeight) {
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002697 delete type;
2698 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002699 return result;
2700}
2701
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002702void SPIRVCodeGenerator::writePrecisionModifier(const Modifiers& modifiers, SpvId id) {
2703 if ((modifiers.fFlags & Modifiers::kLowp_Flag) |
2704 (modifiers.fFlags & Modifiers::kMediump_Flag)) {
2705 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2706 }
2707}
2708
ethannicholas5961bc92016-10-12 06:39:56 -07002709#define BUILTIN_IGNORE 9999
Greg Daniel64773e62016-11-22 09:44:03 -05002710void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002711 OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002712 for (size_t i = 0; i < decl.fVars.size(); i++) {
2713 if (decl.fVars[i]->fKind == Statement::kNop_Kind) {
2714 continue;
2715 }
2716 const VarDeclaration& varDecl = (VarDeclaration&) *decl.fVars[i];
2717 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002718 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2719 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002720 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002721 Modifiers::kWriteOnly_Flag |
2722 Modifiers::kCoherent_Flag |
2723 Modifiers::kVolatile_Flag |
2724 Modifiers::kRestrict_Flag)));
ethannicholas5961bc92016-10-12 06:39:56 -07002725 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2726 continue;
2727 }
2728 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2729 kind != Program::kFragment_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002730 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
ethannicholas5961bc92016-10-12 06:39:56 -07002731 continue;
2732 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05002733 if (!var->fReadCount && !var->fWriteCount &&
ethannicholas14fe8cc2016-09-07 13:37:16 -07002734 !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
2735 Modifiers::kOut_Flag |
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002736 Modifiers::kUniform_Flag |
2737 Modifiers::kBuffer_Flag))) {
ethannicholasd598f792016-07-25 10:08:54 -07002738 // variable is dead and not an input / output var (the Vulkan debug layers complain if
2739 // we elide an interface var, even if it's dead)
ethannicholasb3058bd2016-07-01 08:22:01 -07002740 continue;
2741 }
2742 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002743 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002744 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002745 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002746 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002747 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
2748 if (var->fType.kind() == Type::kSampler_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002749 storageClass = SpvStorageClassUniformConstant;
2750 } else {
2751 storageClass = SpvStorageClassUniform;
2752 }
2753 } else {
2754 storageClass = SpvStorageClassPrivate;
2755 }
2756 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002757 fVariableMap[var] = id;
Ethan Nicholas5226b772018-05-03 16:20:41 -04002758 SpvId type;
2759 if (var->fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2760 type = this->getPointerType(Type("sk_in", Type::kArray_Kind,
2761 var->fType.componentType(), fSkInCount),
2762 storageClass);
2763 } else {
2764 type = this->getPointerType(var->fType, storageClass);
2765 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002766 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002767 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002768 this->writePrecisionModifier(var->fModifiers, id);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002769 if (varDecl.fValue) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002770 SkASSERT(!fCurrentBlock);
ethannicholasf789b382016-08-03 12:43:36 -07002771 fCurrentBlock = -1;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002772 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002773 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002774 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002775 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002776 this->writeLayout(var->fModifiers.fLayout, id);
Ethan Nicholas45b0f152017-07-24 14:36:40 -04002777 if (var->fModifiers.fFlags & Modifiers::kFlat_Flag) {
2778 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2779 }
2780 if (var->fModifiers.fFlags & Modifiers::kNoPerspective_Flag) {
2781 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2782 fDecorationBuffer);
2783 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002784 }
2785}
2786
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002787void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002788 for (const auto& stmt : decl.fVars) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002789 SkASSERT(stmt->fKind == Statement::kVarDeclaration_Kind);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002790 VarDeclaration& varDecl = (VarDeclaration&) *stmt;
2791 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002792 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2793 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002794 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002795 Modifiers::kWriteOnly_Flag |
2796 Modifiers::kCoherent_Flag |
2797 Modifiers::kVolatile_Flag |
2798 Modifiers::kRestrict_Flag)));
ethannicholasb3058bd2016-07-01 08:22:01 -07002799 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002800 fVariableMap[var] = id;
2801 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002802 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002803 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002804 if (varDecl.fValue) {
2805 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002806 this->writeInstruction(SpvOpStore, id, value, out);
2807 }
2808 }
2809}
2810
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002811void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002812 switch (s.fKind) {
Ethan Nicholascb670962017-04-20 19:31:52 -04002813 case Statement::kNop_Kind:
2814 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002815 case Statement::kBlock_Kind:
2816 this->writeBlock((Block&) s, out);
2817 break;
2818 case Statement::kExpression_Kind:
2819 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2820 break;
Greg Daniel64773e62016-11-22 09:44:03 -05002821 case Statement::kReturn_Kind:
ethannicholasb3058bd2016-07-01 08:22:01 -07002822 this->writeReturnStatement((ReturnStatement&) s, out);
2823 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002824 case Statement::kVarDeclarations_Kind:
2825 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002826 break;
2827 case Statement::kIf_Kind:
2828 this->writeIfStatement((IfStatement&) s, out);
2829 break;
2830 case Statement::kFor_Kind:
2831 this->writeForStatement((ForStatement&) s, out);
2832 break;
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002833 case Statement::kWhile_Kind:
2834 this->writeWhileStatement((WhileStatement&) s, out);
2835 break;
2836 case Statement::kDo_Kind:
2837 this->writeDoStatement((DoStatement&) s, out);
2838 break;
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002839 case Statement::kSwitch_Kind:
2840 this->writeSwitchStatement((SwitchStatement&) s, out);
2841 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002842 case Statement::kBreak_Kind:
2843 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2844 break;
2845 case Statement::kContinue_Kind:
2846 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2847 break;
2848 case Statement::kDiscard_Kind:
2849 this->writeInstruction(SpvOpKill, out);
2850 break;
2851 default:
2852 ABORT("unsupported statement: %s", s.description().c_str());
2853 }
2854}
2855
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002856void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002857 for (size_t i = 0; i < b.fStatements.size(); i++) {
2858 this->writeStatement(*b.fStatements[i], out);
2859 }
2860}
2861
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002862void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002863 SpvId test = this->writeExpression(*stmt.fTest, out);
2864 SpvId ifTrue = this->nextId();
2865 SpvId ifFalse = this->nextId();
2866 if (stmt.fIfFalse) {
2867 SpvId end = this->nextId();
2868 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2869 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2870 this->writeLabel(ifTrue, out);
2871 this->writeStatement(*stmt.fIfTrue, out);
2872 if (fCurrentBlock) {
2873 this->writeInstruction(SpvOpBranch, end, out);
2874 }
2875 this->writeLabel(ifFalse, out);
2876 this->writeStatement(*stmt.fIfFalse, out);
2877 if (fCurrentBlock) {
2878 this->writeInstruction(SpvOpBranch, end, out);
2879 }
2880 this->writeLabel(end, out);
2881 } else {
2882 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2883 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2884 this->writeLabel(ifTrue, out);
2885 this->writeStatement(*stmt.fIfTrue, out);
2886 if (fCurrentBlock) {
2887 this->writeInstruction(SpvOpBranch, ifFalse, out);
2888 }
2889 this->writeLabel(ifFalse, out);
2890 }
2891}
2892
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002893void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002894 if (f.fInitializer) {
2895 this->writeStatement(*f.fInitializer, out);
2896 }
2897 SpvId header = this->nextId();
2898 SpvId start = this->nextId();
2899 SpvId body = this->nextId();
2900 SpvId next = this->nextId();
2901 fContinueTarget.push(next);
2902 SpvId end = this->nextId();
2903 fBreakTarget.push(end);
2904 this->writeInstruction(SpvOpBranch, header, out);
2905 this->writeLabel(header, out);
2906 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002907 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002908 this->writeLabel(start, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002909 if (f.fTest) {
2910 SpvId test = this->writeExpression(*f.fTest, out);
2911 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2912 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002913 this->writeLabel(body, out);
2914 this->writeStatement(*f.fStatement, out);
2915 if (fCurrentBlock) {
2916 this->writeInstruction(SpvOpBranch, next, out);
2917 }
2918 this->writeLabel(next, out);
2919 if (f.fNext) {
2920 this->writeExpression(*f.fNext, out);
2921 }
2922 this->writeInstruction(SpvOpBranch, header, out);
2923 this->writeLabel(end, out);
2924 fBreakTarget.pop();
2925 fContinueTarget.pop();
2926}
2927
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002928void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002929 // We believe the while loop code below will work, but Skia doesn't actually use them and
2930 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2931 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2932 // message, simply remove the error call below to see whether our while loop support actually
2933 // works.
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002934 fErrors.error(w.fOffset, "internal error: while loop support has been disabled in SPIR-V, "
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002935 "see SkSLSPIRVCodeGenerator.cpp for details");
2936
2937 SpvId header = this->nextId();
2938 SpvId start = this->nextId();
2939 SpvId body = this->nextId();
2940 fContinueTarget.push(start);
2941 SpvId end = this->nextId();
2942 fBreakTarget.push(end);
2943 this->writeInstruction(SpvOpBranch, header, out);
2944 this->writeLabel(header, out);
2945 this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out);
2946 this->writeInstruction(SpvOpBranch, start, out);
2947 this->writeLabel(start, out);
2948 SpvId test = this->writeExpression(*w.fTest, out);
2949 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2950 this->writeLabel(body, out);
2951 this->writeStatement(*w.fStatement, out);
2952 if (fCurrentBlock) {
2953 this->writeInstruction(SpvOpBranch, start, out);
2954 }
2955 this->writeLabel(end, out);
2956 fBreakTarget.pop();
2957 fContinueTarget.pop();
2958}
2959
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002960void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002961 // We believe the do loop code below will work, but Skia doesn't actually use them and
2962 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2963 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2964 // message, simply remove the error call below to see whether our do loop support actually
2965 // works.
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002966 fErrors.error(d.fOffset, "internal error: do loop support has been disabled in SPIR-V, see "
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002967 "SkSLSPIRVCodeGenerator.cpp for details");
2968
2969 SpvId header = this->nextId();
2970 SpvId start = this->nextId();
2971 SpvId next = this->nextId();
2972 fContinueTarget.push(next);
2973 SpvId end = this->nextId();
2974 fBreakTarget.push(end);
2975 this->writeInstruction(SpvOpBranch, header, out);
2976 this->writeLabel(header, out);
2977 this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out);
2978 this->writeInstruction(SpvOpBranch, start, out);
2979 this->writeLabel(start, out);
2980 this->writeStatement(*d.fStatement, out);
2981 if (fCurrentBlock) {
2982 this->writeInstruction(SpvOpBranch, next, out);
2983 }
2984 this->writeLabel(next, out);
2985 SpvId test = this->writeExpression(*d.fTest, out);
2986 this->writeInstruction(SpvOpBranchConditional, test, start, end, out);
2987 this->writeLabel(end, out);
2988 fBreakTarget.pop();
2989 fContinueTarget.pop();
2990}
2991
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002992void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
2993 SpvId value = this->writeExpression(*s.fValue, out);
2994 std::vector<SpvId> labels;
2995 SpvId end = this->nextId();
2996 SpvId defaultLabel = end;
2997 fBreakTarget.push(end);
2998 int size = 3;
2999 for (const auto& c : s.fCases) {
3000 SpvId label = this->nextId();
3001 labels.push_back(label);
3002 if (c->fValue) {
3003 size += 2;
3004 } else {
3005 defaultLabel = label;
3006 }
3007 }
3008 labels.push_back(end);
3009 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3010 this->writeOpCode(SpvOpSwitch, size, out);
3011 this->writeWord(value, out);
3012 this->writeWord(defaultLabel, out);
3013 for (size_t i = 0; i < s.fCases.size(); ++i) {
3014 if (!s.fCases[i]->fValue) {
3015 continue;
3016 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003017 SkASSERT(s.fCases[i]->fValue->fKind == Expression::kIntLiteral_Kind);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003018 this->writeWord(((IntLiteral&) *s.fCases[i]->fValue).fValue, out);
3019 this->writeWord(labels[i], out);
3020 }
3021 for (size_t i = 0; i < s.fCases.size(); ++i) {
3022 this->writeLabel(labels[i], out);
3023 for (const auto& stmt : s.fCases[i]->fStatements) {
3024 this->writeStatement(*stmt, out);
3025 }
3026 if (fCurrentBlock) {
3027 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3028 }
3029 }
3030 this->writeLabel(end, out);
3031 fBreakTarget.pop();
3032}
3033
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003034void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003035 if (r.fExpression) {
Greg Daniel64773e62016-11-22 09:44:03 -05003036 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003037 out);
3038 } else {
3039 this->writeInstruction(SpvOpReturn, out);
3040 }
3041}
3042
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003043void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003044 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003045 int invocations = 1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003046 for (const auto& e : fProgram) {
3047 if (e.fKind == ProgramElement::kModifiers_Kind) {
3048 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003049 if (m.fFlags & Modifiers::kIn_Flag) {
3050 if (m.fLayout.fInvocations != -1) {
3051 invocations = m.fLayout.fInvocations;
3052 }
3053 SpvId input;
3054 switch (m.fLayout.fPrimitive) {
3055 case Layout::kPoints_Primitive:
3056 input = SpvExecutionModeInputPoints;
3057 break;
3058 case Layout::kLines_Primitive:
3059 input = SpvExecutionModeInputLines;
3060 break;
3061 case Layout::kLinesAdjacency_Primitive:
3062 input = SpvExecutionModeInputLinesAdjacency;
3063 break;
3064 case Layout::kTriangles_Primitive:
3065 input = SpvExecutionModeTriangles;
3066 break;
3067 case Layout::kTrianglesAdjacency_Primitive:
3068 input = SpvExecutionModeInputTrianglesAdjacency;
3069 break;
3070 default:
3071 input = 0;
3072 break;
3073 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003074 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003075 if (input) {
3076 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3077 }
3078 } else if (m.fFlags & Modifiers::kOut_Flag) {
3079 SpvId output;
3080 switch (m.fLayout.fPrimitive) {
3081 case Layout::kPoints_Primitive:
3082 output = SpvExecutionModeOutputPoints;
3083 break;
3084 case Layout::kLineStrip_Primitive:
3085 output = SpvExecutionModeOutputLineStrip;
3086 break;
3087 case Layout::kTriangleStrip_Primitive:
3088 output = SpvExecutionModeOutputTriangleStrip;
3089 break;
3090 default:
3091 output = 0;
3092 break;
3093 }
3094 if (output) {
3095 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3096 }
3097 if (m.fLayout.fMaxVertices != -1) {
3098 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3099 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3100 out);
3101 }
3102 }
3103 }
3104 }
3105 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3106 invocations, out);
3107}
3108
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003109void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003110 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003111 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003112 std::set<SpvId> interfaceVars;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003113 // assign IDs to functions, determine sk_in size
3114 int skInSize = -1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003115 for (const auto& e : program) {
3116 switch (e.fKind) {
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003117 case ProgramElement::kFunction_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003118 FunctionDefinition& f = (FunctionDefinition&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003119 fFunctionMap[&f.fDeclaration] = this->nextId();
3120 break;
3121 }
3122 case ProgramElement::kModifiers_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003123 Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003124 if (m.fFlags & Modifiers::kIn_Flag) {
3125 switch (m.fLayout.fPrimitive) {
3126 case Layout::kPoints_Primitive: // break
3127 case Layout::kLines_Primitive:
3128 skInSize = 1;
3129 break;
3130 case Layout::kLinesAdjacency_Primitive: // break
3131 skInSize = 2;
3132 break;
3133 case Layout::kTriangles_Primitive: // break
3134 case Layout::kTrianglesAdjacency_Primitive:
3135 skInSize = 3;
3136 break;
3137 default:
3138 break;
3139 }
3140 }
3141 break;
3142 }
3143 default:
3144 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003145 }
3146 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003147 for (const auto& e : program) {
3148 if (e.fKind == ProgramElement::kInterfaceBlock_Kind) {
3149 InterfaceBlock& intf = (InterfaceBlock&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003150 if (SK_IN_BUILTIN == intf.fVariable.fModifiers.fLayout.fBuiltin) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003151 SkASSERT(skInSize != -1);
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003152 intf.fSizes.emplace_back(new IntLiteral(fContext, -1, skInSize));
3153 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003154 SpvId id = this->writeInterfaceBlock(intf);
Ethan Nicholas16c11962018-03-16 12:20:54 -04003155 if (((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
3156 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) &&
3157 intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003158 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003159 }
3160 }
3161 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003162 for (const auto& e : program) {
3163 if (e.fKind == ProgramElement::kVar_Kind) {
3164 this->writeGlobalVars(program.fKind, ((VarDeclarations&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003165 }
3166 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003167 for (const auto& e : program) {
3168 if (e.fKind == ProgramElement::kFunction_Kind) {
3169 this->writeFunction(((FunctionDefinition&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003170 }
3171 }
ethannicholasd598f792016-07-25 10:08:54 -07003172 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003173 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07003174 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003175 main = entry.first;
3176 }
3177 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003178 SkASSERT(main);
ethannicholasb3058bd2016-07-01 08:22:01 -07003179 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003180 const Variable* var = entry.first;
Greg Daniel64773e62016-11-22 09:44:03 -05003181 if (var->fStorage == Variable::kGlobal_Storage &&
Ethan Nicholas16c11962018-03-16 12:20:54 -04003182 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
Ethan Nicholasd23c8192018-09-26 17:01:24 -04003183 (var->fModifiers.fFlags & Modifiers::kOut_Flag))) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003184 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003185 }
3186 }
3187 this->writeCapabilities(out);
3188 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3189 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003190 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->fName.fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003191 (int32_t) interfaceVars.size(), out);
3192 switch (program.fKind) {
3193 case Program::kVertex_Kind:
3194 this->writeWord(SpvExecutionModelVertex, out);
3195 break;
3196 case Program::kFragment_Kind:
3197 this->writeWord(SpvExecutionModelFragment, out);
3198 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003199 case Program::kGeometry_Kind:
3200 this->writeWord(SpvExecutionModelGeometry, out);
3201 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003202 default:
3203 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003204 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003205 SpvId entryPoint = fFunctionMap[main];
3206 this->writeWord(entryPoint, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003207 this->writeString(main->fName.fChars, main->fName.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003208 for (int var : interfaceVars) {
3209 this->writeWord(var, out);
3210 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003211 if (program.fKind == Program::kGeometry_Kind) {
3212 this->writeGeometryShaderExecutionMode(entryPoint, out);
3213 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003214 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003215 this->writeInstruction(SpvOpExecutionMode,
3216 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003217 SpvExecutionModeOriginUpperLeft,
3218 out);
3219 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003220 for (const auto& e : program) {
3221 if (e.fKind == ProgramElement::kExtension_Kind) {
3222 this->writeInstruction(SpvOpSourceExtension, ((Extension&) e).fName.c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003223 }
3224 }
Greg Daniel64773e62016-11-22 09:44:03 -05003225
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003226 write_stringstream(fExtraGlobalsBuffer, out);
3227 write_stringstream(fNameBuffer, out);
3228 write_stringstream(fDecorationBuffer, out);
3229 write_stringstream(fConstantBuffer, out);
3230 write_stringstream(fExternalFunctionsBuffer, out);
3231 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003232}
3233
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003234bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003235 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003236 this->writeWord(SpvMagicNumber, *fOut);
3237 this->writeWord(SpvVersion, *fOut);
3238 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003239 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003240 this->writeInstructions(fProgram, buffer);
3241 this->writeWord(fIdCount, *fOut);
3242 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003243 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003244 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003245}
3246
3247}