blob: f0e14ec1caa09ac0b6fbf3b2dadbc5e377d4e0e4 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Ethan Nicholas9bd301d2017-03-31 16:04:34 +00009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "src/sksl/GLSL.std.450.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070011
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "src/sksl/SkSLCompiler.h"
13#include "src/sksl/ir/SkSLExpressionStatement.h"
14#include "src/sksl/ir/SkSLExtension.h"
15#include "src/sksl/ir/SkSLIndexExpression.h"
16#include "src/sksl/ir/SkSLVariableReference.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070017
Ethan Nicholas0be34802019-08-15 12:36:58 -040018#ifdef SK_VULKAN
19#include "src/gpu/vk/GrVkCaps.h"
20#endif
21
ethannicholasb3058bd2016-07-01 08:22:01 -070022namespace SkSL {
23
ethannicholasb3058bd2016-07-01 08:22:01 -070024static const int32_t SKSL_MAGIC = 0x0; // FIXME: we should probably register a magic number
25
26void SPIRVCodeGenerator::setupIntrinsics() {
27#define ALL_GLSL(x) std::make_tuple(kGLSL_STD_450_IntrinsicKind, GLSLstd450 ## x, GLSLstd450 ## x, \
28 GLSLstd450 ## x, GLSLstd450 ## x)
29#define BY_TYPE_GLSL(ifFloat, ifInt, ifUInt) std::make_tuple(kGLSL_STD_450_IntrinsicKind, \
30 GLSLstd450 ## ifFloat, \
31 GLSLstd450 ## ifInt, \
32 GLSLstd450 ## ifUInt, \
33 SpvOpUndef)
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040034#define ALL_SPIRV(x) std::make_tuple(kSPIRV_IntrinsicKind, SpvOp ## x, SpvOp ## x, SpvOp ## x, \
35 SpvOp ## x)
ethannicholasb3058bd2016-07-01 08:22:01 -070036#define SPECIAL(x) std::make_tuple(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic, \
37 k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
38 k ## x ## _SpecialIntrinsic)
Ethan Nicholas0df1b042017-03-31 13:56:23 -040039 fIntrinsicMap[String("round")] = ALL_GLSL(Round);
40 fIntrinsicMap[String("roundEven")] = ALL_GLSL(RoundEven);
41 fIntrinsicMap[String("trunc")] = ALL_GLSL(Trunc);
42 fIntrinsicMap[String("abs")] = BY_TYPE_GLSL(FAbs, SAbs, SAbs);
43 fIntrinsicMap[String("sign")] = BY_TYPE_GLSL(FSign, SSign, SSign);
44 fIntrinsicMap[String("floor")] = ALL_GLSL(Floor);
45 fIntrinsicMap[String("ceil")] = ALL_GLSL(Ceil);
46 fIntrinsicMap[String("fract")] = ALL_GLSL(Fract);
47 fIntrinsicMap[String("radians")] = ALL_GLSL(Radians);
48 fIntrinsicMap[String("degrees")] = ALL_GLSL(Degrees);
49 fIntrinsicMap[String("sin")] = ALL_GLSL(Sin);
50 fIntrinsicMap[String("cos")] = ALL_GLSL(Cos);
51 fIntrinsicMap[String("tan")] = ALL_GLSL(Tan);
52 fIntrinsicMap[String("asin")] = ALL_GLSL(Asin);
53 fIntrinsicMap[String("acos")] = ALL_GLSL(Acos);
54 fIntrinsicMap[String("atan")] = SPECIAL(Atan);
55 fIntrinsicMap[String("sinh")] = ALL_GLSL(Sinh);
56 fIntrinsicMap[String("cosh")] = ALL_GLSL(Cosh);
57 fIntrinsicMap[String("tanh")] = ALL_GLSL(Tanh);
58 fIntrinsicMap[String("asinh")] = ALL_GLSL(Asinh);
59 fIntrinsicMap[String("acosh")] = ALL_GLSL(Acosh);
60 fIntrinsicMap[String("atanh")] = ALL_GLSL(Atanh);
61 fIntrinsicMap[String("pow")] = ALL_GLSL(Pow);
62 fIntrinsicMap[String("exp")] = ALL_GLSL(Exp);
63 fIntrinsicMap[String("log")] = ALL_GLSL(Log);
64 fIntrinsicMap[String("exp2")] = ALL_GLSL(Exp2);
65 fIntrinsicMap[String("log2")] = ALL_GLSL(Log2);
66 fIntrinsicMap[String("sqrt")] = ALL_GLSL(Sqrt);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040067 fIntrinsicMap[String("inverse")] = ALL_GLSL(MatrixInverse);
68 fIntrinsicMap[String("transpose")] = ALL_SPIRV(Transpose);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040069 fIntrinsicMap[String("inversesqrt")] = ALL_GLSL(InverseSqrt);
70 fIntrinsicMap[String("determinant")] = ALL_GLSL(Determinant);
71 fIntrinsicMap[String("matrixInverse")] = ALL_GLSL(MatrixInverse);
Ethan Nicholas70a44b22017-11-30 09:09:16 -050072 fIntrinsicMap[String("mod")] = SPECIAL(Mod);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050073 fIntrinsicMap[String("min")] = SPECIAL(Min);
74 fIntrinsicMap[String("max")] = SPECIAL(Max);
75 fIntrinsicMap[String("clamp")] = SPECIAL(Clamp);
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040076 fIntrinsicMap[String("saturate")] = SPECIAL(Saturate);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040077 fIntrinsicMap[String("dot")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
Ethan Nicholas0187ae62017-05-03 11:03:44 -040078 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050079 fIntrinsicMap[String("mix")] = SPECIAL(Mix);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040080 fIntrinsicMap[String("step")] = ALL_GLSL(Step);
81 fIntrinsicMap[String("smoothstep")] = ALL_GLSL(SmoothStep);
82 fIntrinsicMap[String("fma")] = ALL_GLSL(Fma);
83 fIntrinsicMap[String("frexp")] = ALL_GLSL(Frexp);
84 fIntrinsicMap[String("ldexp")] = ALL_GLSL(Ldexp);
ethannicholasb3058bd2016-07-01 08:22:01 -070085
Ethan Nicholas0df1b042017-03-31 13:56:23 -040086#define PACK(type) fIntrinsicMap[String("pack" #type)] = ALL_GLSL(Pack ## type); \
87 fIntrinsicMap[String("unpack" #type)] = ALL_GLSL(Unpack ## type)
ethannicholasb3058bd2016-07-01 08:22:01 -070088 PACK(Snorm4x8);
89 PACK(Unorm4x8);
90 PACK(Snorm2x16);
91 PACK(Unorm2x16);
92 PACK(Half2x16);
93 PACK(Double2x32);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040094 fIntrinsicMap[String("length")] = ALL_GLSL(Length);
95 fIntrinsicMap[String("distance")] = ALL_GLSL(Distance);
96 fIntrinsicMap[String("cross")] = ALL_GLSL(Cross);
97 fIntrinsicMap[String("normalize")] = ALL_GLSL(Normalize);
98 fIntrinsicMap[String("faceForward")] = ALL_GLSL(FaceForward);
99 fIntrinsicMap[String("reflect")] = ALL_GLSL(Reflect);
100 fIntrinsicMap[String("refract")] = ALL_GLSL(Refract);
101 fIntrinsicMap[String("findLSB")] = ALL_GLSL(FindILsb);
102 fIntrinsicMap[String("findMSB")] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
103 fIntrinsicMap[String("dFdx")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400104 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700105 fIntrinsicMap[String("dFdy")] = SPECIAL(DFdy);
Chris Dalton09212192018-11-13 15:07:24 -0500106 fIntrinsicMap[String("fwidth")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFwidth,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400107 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400108 fIntrinsicMap[String("makeSampler2D")] = SPECIAL(SampledImage);
109
Ethan Nicholas13863662019-07-29 13:05:15 -0400110 fIntrinsicMap[String("sample")] = SPECIAL(Texture);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400111 fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
Greg Daniel64773e62016-11-22 09:44:03 -0500112
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400113 fIntrinsicMap[String("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400114 SpvOpUndef, SpvOpUndef, SpvOpAny);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400115 fIntrinsicMap[String("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400116 SpvOpUndef, SpvOpUndef, SpvOpAll);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400117 fIntrinsicMap[String("equal")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400118 SpvOpFOrdEqual, SpvOpIEqual,
119 SpvOpIEqual, SpvOpLogicalEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400120 fIntrinsicMap[String("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400121 SpvOpFOrdNotEqual, SpvOpINotEqual,
122 SpvOpINotEqual,
123 SpvOpLogicalNotEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400124 fIntrinsicMap[String("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500125 SpvOpFOrdLessThan, SpvOpSLessThan,
126 SpvOpULessThan, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400127 fIntrinsicMap[String("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500128 SpvOpFOrdLessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400129 SpvOpSLessThanEqual,
130 SpvOpULessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400131 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400132 fIntrinsicMap[String("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500133 SpvOpFOrdGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400134 SpvOpSGreaterThan,
135 SpvOpUGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400136 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400137 fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500138 SpvOpFOrdGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400139 SpvOpSGreaterThanEqual,
140 SpvOpUGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400141 SpvOpUndef);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400142 fIntrinsicMap[String("EmitVertex")] = ALL_SPIRV(EmitVertex);
143 fIntrinsicMap[String("EndPrimitive")] = ALL_SPIRV(EndPrimitive);
ethannicholasb3058bd2016-07-01 08:22:01 -0700144// interpolateAt* not yet supported...
145}
146
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400147void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700148 out.write((const char*) &word, sizeof(word));
ethannicholasb3058bd2016-07-01 08:22:01 -0700149}
150
ethannicholasd598f792016-07-25 10:08:54 -0700151static bool is_float(const Context& context, const Type& type) {
Ethan Nicholas0df21132018-07-10 09:37:51 -0400152 if (type.columns() > 1) {
ethannicholasd598f792016-07-25 10:08:54 -0700153 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700154 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400155 return type == *context.fFloat_Type || type == *context.fHalf_Type ||
156 type == *context.fDouble_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700157}
158
ethannicholasd598f792016-07-25 10:08:54 -0700159static bool is_signed(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700160 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700161 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700162 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400163 return type == *context.fInt_Type || type == *context.fShort_Type ||
164 type == *context.fByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700165}
166
ethannicholasd598f792016-07-25 10:08:54 -0700167static bool is_unsigned(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700168 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700169 return is_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700170 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400171 return type == *context.fUInt_Type || type == *context.fUShort_Type ||
172 type == *context.fUByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700173}
174
ethannicholasd598f792016-07-25 10:08:54 -0700175static bool is_bool(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700176 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700177 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700178 }
ethannicholasd598f792016-07-25 10:08:54 -0700179 return type == *context.fBool_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700180}
181
ethannicholasd598f792016-07-25 10:08:54 -0700182static bool is_out(const Variable& var) {
183 return (var.fModifiers.fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700184}
185
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400186void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400187 SkASSERT(opCode != SpvOpLoad || &out != &fConstantBuffer);
188 SkASSERT(opCode != SpvOpUndef);
ethannicholasb3058bd2016-07-01 08:22:01 -0700189 switch (opCode) {
190 case SpvOpReturn: // fall through
191 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700192 case SpvOpKill: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700193 case SpvOpBranch: // fall through
194 case SpvOpBranchConditional:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400195 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700196 fCurrentBlock = 0;
197 break;
198 case SpvOpConstant: // fall through
199 case SpvOpConstantTrue: // fall through
200 case SpvOpConstantFalse: // fall through
201 case SpvOpConstantComposite: // fall through
202 case SpvOpTypeVoid: // fall through
203 case SpvOpTypeInt: // fall through
204 case SpvOpTypeFloat: // fall through
205 case SpvOpTypeBool: // fall through
206 case SpvOpTypeVector: // fall through
207 case SpvOpTypeMatrix: // fall through
208 case SpvOpTypeArray: // fall through
209 case SpvOpTypePointer: // fall through
210 case SpvOpTypeFunction: // fall through
211 case SpvOpTypeRuntimeArray: // fall through
212 case SpvOpTypeStruct: // fall through
213 case SpvOpTypeImage: // fall through
214 case SpvOpTypeSampledImage: // fall through
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400215 case SpvOpTypeSampler: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700216 case SpvOpVariable: // fall through
217 case SpvOpFunction: // fall through
218 case SpvOpFunctionParameter: // fall through
219 case SpvOpFunctionEnd: // fall through
220 case SpvOpExecutionMode: // fall through
221 case SpvOpMemoryModel: // fall through
222 case SpvOpCapability: // fall through
223 case SpvOpExtInstImport: // fall through
224 case SpvOpEntryPoint: // fall through
225 case SpvOpSource: // fall through
226 case SpvOpSourceExtension: // fall through
227 case SpvOpName: // fall through
228 case SpvOpMemberName: // fall through
229 case SpvOpDecorate: // fall through
230 case SpvOpMemberDecorate:
231 break;
232 default:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400233 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700234 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700235 this->writeWord((length << 16) | opCode, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700236}
237
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400238void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700239 fCurrentBlock = label;
240 this->writeInstruction(SpvOpLabel, label, out);
241}
242
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400243void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700244 this->writeOpCode(opCode, 1, out);
245}
246
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400247void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700248 this->writeOpCode(opCode, 2, out);
249 this->writeWord(word1, out);
250}
251
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700252void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputStream& out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400253 out.write(string, length);
ethannicholasb3058bd2016-07-01 08:22:01 -0700254 switch (length % 4) {
255 case 1:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500256 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700257 // fall through
258 case 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500259 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700260 // fall through
261 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500262 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700263 break;
264 default:
265 this->writeWord(0, out);
266 }
267}
268
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700269void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out) {
270 this->writeOpCode(opCode, 1 + (string.fLength + 4) / 4, out);
271 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700272}
273
274
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700275void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400276 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700277 this->writeOpCode(opCode, 2 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700278 this->writeWord(word1, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700279 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700280}
281
Greg Daniel64773e62016-11-22 09:44:03 -0500282void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700283 StringFragment string, OutputStream& out) {
284 this->writeOpCode(opCode, 3 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700285 this->writeWord(word1, out);
286 this->writeWord(word2, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700287 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700288}
289
Greg Daniel64773e62016-11-22 09:44:03 -0500290void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400291 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700292 this->writeOpCode(opCode, 3, out);
293 this->writeWord(word1, out);
294 this->writeWord(word2, out);
295}
296
Greg Daniel64773e62016-11-22 09:44:03 -0500297void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400298 int32_t word3, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700299 this->writeOpCode(opCode, 4, out);
300 this->writeWord(word1, out);
301 this->writeWord(word2, out);
302 this->writeWord(word3, out);
303}
304
Greg Daniel64773e62016-11-22 09:44:03 -0500305void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400306 int32_t word3, int32_t word4, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700307 this->writeOpCode(opCode, 5, out);
308 this->writeWord(word1, out);
309 this->writeWord(word2, out);
310 this->writeWord(word3, out);
311 this->writeWord(word4, out);
312}
313
Greg Daniel64773e62016-11-22 09:44:03 -0500314void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
315 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400316 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700317 this->writeOpCode(opCode, 6, out);
318 this->writeWord(word1, out);
319 this->writeWord(word2, out);
320 this->writeWord(word3, out);
321 this->writeWord(word4, out);
322 this->writeWord(word5, out);
323}
324
Greg Daniel64773e62016-11-22 09:44:03 -0500325void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700326 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400327 int32_t word6, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700328 this->writeOpCode(opCode, 7, out);
329 this->writeWord(word1, out);
330 this->writeWord(word2, out);
331 this->writeWord(word3, out);
332 this->writeWord(word4, out);
333 this->writeWord(word5, out);
334 this->writeWord(word6, out);
335}
336
Greg Daniel64773e62016-11-22 09:44:03 -0500337void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700338 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400339 int32_t word6, int32_t word7, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700340 this->writeOpCode(opCode, 8, out);
341 this->writeWord(word1, out);
342 this->writeWord(word2, out);
343 this->writeWord(word3, out);
344 this->writeWord(word4, out);
345 this->writeWord(word5, out);
346 this->writeWord(word6, out);
347 this->writeWord(word7, out);
348}
349
Greg Daniel64773e62016-11-22 09:44:03 -0500350void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700351 int32_t word3, int32_t word4, int32_t word5,
352 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400353 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700354 this->writeOpCode(opCode, 9, out);
355 this->writeWord(word1, out);
356 this->writeWord(word2, out);
357 this->writeWord(word3, out);
358 this->writeWord(word4, out);
359 this->writeWord(word5, out);
360 this->writeWord(word6, out);
361 this->writeWord(word7, out);
362 this->writeWord(word8, out);
363}
364
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400365void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700366 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
367 if (fCapabilities & bit) {
368 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
369 }
370 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400371 if (fProgram.fKind == Program::kGeometry_Kind) {
372 this->writeInstruction(SpvOpCapability, SpvCapabilityGeometry, out);
373 }
Ethan Nicholas81d15112018-07-13 12:48:50 -0400374 else {
375 this->writeInstruction(SpvOpCapability, SpvCapabilityShader, out);
376 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700377}
378
379SpvId SPIRVCodeGenerator::nextId() {
380 return fIdCount++;
381}
382
Ethan Nicholas19671772016-11-28 16:30:17 -0500383void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
384 SpvId resultId) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700385 this->writeInstruction(SpvOpName, resultId, type.name().c_str(), fNameBuffer);
386 // go ahead and write all of the field types, so we don't inadvertently write them while we're
387 // in the middle of writing the struct instruction
388 std::vector<SpvId> types;
389 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500390 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700391 }
392 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
393 this->writeWord(resultId, fConstantBuffer);
394 for (SpvId id : types) {
395 this->writeWord(id, fConstantBuffer);
396 }
397 size_t offset = 0;
398 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400399 const Type::Field& field = type.fields()[i];
400 size_t size = memoryLayout.size(*field.fType);
401 size_t alignment = memoryLayout.alignment(*field.fType);
402 const Layout& fieldLayout = field.fModifiers.fLayout;
Ethan Nicholas19671772016-11-28 16:30:17 -0500403 if (fieldLayout.fOffset >= 0) {
Greg Danieldbd44c72017-01-24 15:12:12 -0500404 if (fieldLayout.fOffset < (int) offset) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700405 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400406 "offset of field '" + field.fName + "' must be at "
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500407 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -0500408 }
409 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700410 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400411 "offset of field '" + field.fName + "' must be a multiple"
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500412 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -0500413 }
414 offset = fieldLayout.fOffset;
415 } else {
416 size_t mod = offset % alignment;
417 if (mod) {
418 offset += alignment - mod;
419 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700420 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400421 this->writeInstruction(SpvOpMemberName, resultId, i, field.fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500422 this->writeLayout(fieldLayout, resultId, i);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400423 if (field.fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -0500424 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700425 (SpvId) offset, fDecorationBuffer);
426 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400427 if (field.fType->kind() == Type::kMatrix_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -0500428 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -0700429 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500430 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400431 (SpvId) memoryLayout.stride(*field.fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800432 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700433 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400434 if (!field.fType->highPrecision()) {
435 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i,
436 SpvDecorationRelaxedPrecision, fDecorationBuffer);
437 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700438 offset += size;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400439 Type::Kind kind = field.fType->kind();
ethannicholasb3058bd2016-07-01 08:22:01 -0700440 if ((kind == Type::kArray_Kind || kind == Type::kStruct_Kind) && offset % alignment != 0) {
441 offset += alignment - offset % alignment;
442 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700443 }
444}
445
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400446Type SPIRVCodeGenerator::getActualType(const Type& type) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500447 if (type.isFloat()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400448 return *fContext.fFloat_Type;
449 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500450 if (type.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400451 return *fContext.fInt_Type;
452 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500453 if (type.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400454 return *fContext.fUInt_Type;
455 }
456 if (type.kind() == Type::kMatrix_Kind || type.kind() == Type::kVector_Kind) {
457 if (type.componentType() == *fContext.fHalf_Type) {
458 return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
459 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400460 if (type.componentType() == *fContext.fShort_Type ||
461 type.componentType() == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400462 return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
463 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400464 if (type.componentType() == *fContext.fUShort_Type ||
465 type.componentType() == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400466 return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
467 }
468 }
469 return type;
470}
471
ethannicholasb3058bd2016-07-01 08:22:01 -0700472SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800473 return this->getType(type, fDefaultLayout);
474}
475
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400476SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
477 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400478 String key = type.name() + to_string((int) layout.fStd);
ethannicholas8ac838d2016-11-22 08:39:36 -0800479 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700480 if (entry == fTypeMap.end()) {
481 SpvId result = this->nextId();
482 switch (type.kind()) {
483 case Type::kScalar_Kind:
ethannicholasd598f792016-07-25 10:08:54 -0700484 if (type == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700485 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500486 } else if (type == *fContext.fInt_Type || type == *fContext.fShort_Type ||
487 type == *fContext.fIntLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700488 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500489 } else if (type == *fContext.fUInt_Type || type == *fContext.fUShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700490 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500491 } else if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type ||
492 type == *fContext.fFloatLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700493 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -0700494 } else if (type == *fContext.fDouble_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700495 this->writeInstruction(SpvOpTypeFloat, result, 64, fConstantBuffer);
496 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400497 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700498 }
499 break;
500 case Type::kVector_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500501 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800502 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700503 type.columns(), fConstantBuffer);
504 break;
505 case Type::kMatrix_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500506 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800507 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700508 type.columns(), fConstantBuffer);
509 break;
510 case Type::kStruct_Kind:
ethannicholas8ac838d2016-11-22 08:39:36 -0800511 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700512 break;
513 case Type::kArray_Kind: {
514 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700515 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500516 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800517 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700518 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500519 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400520 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800521 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700522 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400523 SkASSERT(false); // we shouldn't have any runtime-sized arrays right now
Greg Daniel64773e62016-11-22 09:44:03 -0500524 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800525 this->getType(type.componentType(), layout),
526 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400527 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
528 (int32_t) layout.stride(type),
529 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700530 }
531 break;
532 }
533 case Type::kSampler_Kind: {
Greg Daniel64773e62016-11-22 09:44:03 -0500534 SpvId image = result;
535 if (SpvDimSubpassData != type.dimensions()) {
Stephen White792e2302019-08-09 13:33:51 -0400536 image = this->getType(type.textureType(), layout);
Greg Daniel64773e62016-11-22 09:44:03 -0500537 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400538 if (SpvDimBuffer == type.dimensions()) {
539 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
540 }
Greg Daniel64773e62016-11-22 09:44:03 -0500541 if (SpvDimSubpassData != type.dimensions()) {
542 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
543 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700544 break;
545 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400546 case Type::kSeparateSampler_Kind: {
547 this->writeInstruction(SpvOpTypeSampler, result, fConstantBuffer);
548 break;
549 }
550 case Type::kTexture_Kind: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400551 this->writeInstruction(SpvOpTypeImage, result,
552 this->getType(*fContext.fFloat_Type, layout),
Stephen White792e2302019-08-09 13:33:51 -0400553 type.dimensions(), type.isDepth(), type.isArrayed(),
554 type.isMultisampled(), type.isSampled() ? 1 : 2,
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400555 SpvImageFormatUnknown, fConstantBuffer);
556 fImageTypeMap[key] = result;
557 break;
558 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700559 default:
ethannicholasd598f792016-07-25 10:08:54 -0700560 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700561 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
562 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500563#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700564 ABORT("invalid type: %s", type.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500565#endif
ethannicholasb3058bd2016-07-01 08:22:01 -0700566 }
567 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800568 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700569 return result;
570 }
571 return entry->second;
572}
573
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400574SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400575 SkASSERT(type.kind() == Type::kSampler_Kind);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400576 this->getType(type);
577 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400578 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400579 return fImageTypeMap[key];
580}
581
ethannicholasd598f792016-07-25 10:08:54 -0700582SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Brian Osmanc4f937b2020-03-25 15:39:07 -0400583 String key = to_string(this->getType(function.fReturnType)) + "(";
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400584 String separator;
ethannicholasd598f792016-07-25 10:08:54 -0700585 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700586 key += separator;
587 separator = ", ";
Brian Osmanc4f937b2020-03-25 15:39:07 -0400588 key += to_string(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700589 }
590 key += ")";
591 auto entry = fTypeMap.find(key);
592 if (entry == fTypeMap.end()) {
593 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -0700594 int32_t length = 3 + (int32_t) function.fParameters.size();
595 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700596 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -0700597 for (size_t i = 0; i < function.fParameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500598 // glslang seems to treat all function arguments as pointers whether they need to be or
599 // not. I was initially puzzled by this until I ran bizarre failures with certain
600 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700601 // failure case:
602 //
603 // void sphere(float x) {
604 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500605 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700606 // void map() {
607 // sphere(1.0);
608 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500609 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700610 // void main() {
611 // for (int i = 0; i < 1; i++) {
612 // map();
613 // }
614 // }
615 //
Greg Daniel64773e62016-11-22 09:44:03 -0500616 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
617 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700618 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
619 // the spec makes this make sense.
620// if (is_out(function->fParameters[i])) {
ethannicholasd598f792016-07-25 10:08:54 -0700621 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -0700622 SpvStorageClassFunction));
623// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700624// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700625// }
626 }
627 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
628 this->writeWord(result, fConstantBuffer);
629 this->writeWord(returnType, fConstantBuffer);
630 for (SpvId id : parameterTypes) {
631 this->writeWord(id, fConstantBuffer);
632 }
633 fTypeMap[key] = result;
634 return result;
635 }
636 return entry->second;
637}
638
ethannicholas8ac838d2016-11-22 08:39:36 -0800639SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
640 return this->getPointerType(type, fDefaultLayout, storageClass);
641}
642
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400643SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700644 SpvStorageClass_ storageClass) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400645 Type type = this->getActualType(rawType);
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500646 String key = type.displayName() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700647 auto entry = fTypeMap.find(key);
648 if (entry == fTypeMap.end()) {
649 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500650 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700651 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700652 fTypeMap[key] = result;
653 return result;
654 }
655 return entry->second;
656}
657
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400658SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700659 switch (expr.fKind) {
660 case Expression::kBinary_Kind:
661 return this->writeBinaryExpression((BinaryExpression&) expr, out);
662 case Expression::kBoolLiteral_Kind:
663 return this->writeBoolLiteral((BoolLiteral&) expr);
664 case Expression::kConstructor_Kind:
665 return this->writeConstructor((Constructor&) expr, out);
666 case Expression::kIntLiteral_Kind:
667 return this->writeIntLiteral((IntLiteral&) expr);
668 case Expression::kFieldAccess_Kind:
669 return this->writeFieldAccess(((FieldAccess&) expr), out);
670 case Expression::kFloatLiteral_Kind:
671 return this->writeFloatLiteral(((FloatLiteral&) expr));
672 case Expression::kFunctionCall_Kind:
673 return this->writeFunctionCall((FunctionCall&) expr, out);
674 case Expression::kPrefix_Kind:
675 return this->writePrefixExpression((PrefixExpression&) expr, out);
676 case Expression::kPostfix_Kind:
677 return this->writePostfixExpression((PostfixExpression&) expr, out);
678 case Expression::kSwizzle_Kind:
679 return this->writeSwizzle((Swizzle&) expr, out);
680 case Expression::kVariableReference_Kind:
681 return this->writeVariableReference((VariableReference&) expr, out);
682 case Expression::kTernary_Kind:
683 return this->writeTernaryExpression((TernaryExpression&) expr, out);
684 case Expression::kIndex_Kind:
685 return this->writeIndexExpression((IndexExpression&) expr, out);
686 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500687#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700688 ABORT("unsupported expression: %s", expr.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500689#endif
690 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700691 }
692 return -1;
693}
694
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400695SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700696 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400697 SkASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -0700698 int32_t intrinsicId;
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400699 if (c.fArguments.size() > 0) {
700 const Type& type = c.fArguments[0]->fType;
701 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
702 intrinsicId = std::get<1>(intrinsic->second);
703 } else if (is_signed(fContext, type)) {
704 intrinsicId = std::get<2>(intrinsic->second);
705 } else if (is_unsigned(fContext, type)) {
706 intrinsicId = std::get<3>(intrinsic->second);
707 } else if (is_bool(fContext, type)) {
708 intrinsicId = std::get<4>(intrinsic->second);
709 } else {
710 intrinsicId = std::get<1>(intrinsic->second);
711 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700712 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400713 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700714 }
715 switch (std::get<0>(intrinsic->second)) {
716 case kGLSL_STD_450_IntrinsicKind: {
717 SpvId result = this->nextId();
718 std::vector<SpvId> arguments;
719 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400720 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
721 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
722 } else {
723 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
724 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700725 }
726 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700727 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700728 this->writeWord(result, out);
729 this->writeWord(fGLSLExtendedInstructions, out);
730 this->writeWord(intrinsicId, out);
731 for (SpvId id : arguments) {
732 this->writeWord(id, out);
733 }
734 return result;
735 }
736 case kSPIRV_IntrinsicKind: {
737 SpvId result = this->nextId();
738 std::vector<SpvId> arguments;
739 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400740 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
741 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
742 } else {
743 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
744 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700745 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400746 if (c.fType != *fContext.fVoid_Type) {
747 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
748 this->writeWord(this->getType(c.fType), out);
749 this->writeWord(result, out);
750 } else {
751 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
752 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700753 for (SpvId id : arguments) {
754 this->writeWord(id, out);
755 }
756 return result;
757 }
758 case kSpecial_IntrinsicKind:
759 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
760 default:
761 ABORT("unsupported intrinsic kind");
762 }
763}
764
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500765std::vector<SpvId> SPIRVCodeGenerator::vectorize(
766 const std::vector<std::unique_ptr<Expression>>& args,
767 OutputStream& out) {
768 int vectorSize = 0;
769 for (const auto& a : args) {
770 if (a->fType.kind() == Type::kVector_Kind) {
771 if (vectorSize) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400772 SkASSERT(a->fType.columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500773 }
774 else {
775 vectorSize = a->fType.columns();
776 }
777 }
778 }
779 std::vector<SpvId> result;
780 for (const auto& a : args) {
781 SpvId raw = this->writeExpression(*a, out);
782 if (vectorSize && a->fType.kind() == Type::kScalar_Kind) {
783 SpvId vector = this->nextId();
784 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
785 this->writeWord(this->getType(a->fType.toCompound(fContext, vectorSize, 1)), out);
786 this->writeWord(vector, out);
787 for (int i = 0; i < vectorSize; i++) {
788 this->writeWord(raw, out);
789 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400790 this->writePrecisionModifier(a->fType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500791 result.push_back(vector);
792 } else {
793 result.push_back(raw);
794 }
795 }
796 return result;
797}
798
799void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
800 SpvId signedInst, SpvId unsignedInst,
801 const std::vector<SpvId>& args,
802 OutputStream& out) {
803 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
804 this->writeWord(this->getType(type), out);
805 this->writeWord(id, out);
806 this->writeWord(fGLSLExtendedInstructions, out);
807
808 if (is_float(fContext, type)) {
809 this->writeWord(floatInst, out);
810 } else if (is_signed(fContext, type)) {
811 this->writeWord(signedInst, out);
812 } else if (is_unsigned(fContext, type)) {
813 this->writeWord(unsignedInst, out);
814 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400815 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500816 }
817 for (SpvId a : args) {
818 this->writeWord(a, out);
819 }
820}
821
Greg Daniel64773e62016-11-22 09:44:03 -0500822SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400823 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700824 SpvId result = this->nextId();
825 switch (kind) {
826 case kAtan_SpecialIntrinsic: {
827 std::vector<SpvId> arguments;
828 for (size_t i = 0; i < c.fArguments.size(); i++) {
829 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
830 }
831 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700832 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700833 this->writeWord(result, out);
834 this->writeWord(fGLSLExtendedInstructions, out);
835 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
836 for (SpvId id : arguments) {
837 this->writeWord(id, out);
838 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400839 break;
840 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400841 case kSampledImage_SpecialIntrinsic: {
842 SkASSERT(2 == c.fArguments.size());
843 SpvId img = this->writeExpression(*c.fArguments[0], out);
844 SpvId sampler = this->writeExpression(*c.fArguments[1], out);
845 this->writeInstruction(SpvOpSampledImage,
846 this->getType(c.fType),
847 result,
848 img,
849 sampler,
850 out);
851 break;
852 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400853 case kSubpassLoad_SpecialIntrinsic: {
854 SpvId img = this->writeExpression(*c.fArguments[0], out);
855 std::vector<std::unique_ptr<Expression>> args;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700856 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
857 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
858 Constructor ctor(-1, *fContext.fFloat2_Type, std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400859 SpvId coords = this->writeConstantVector(ctor);
860 if (1 == c.fArguments.size()) {
861 this->writeInstruction(SpvOpImageRead,
862 this->getType(c.fType),
863 result,
864 img,
865 coords,
866 out);
867 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400868 SkASSERT(2 == c.fArguments.size());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400869 SpvId sample = this->writeExpression(*c.fArguments[1], out);
870 this->writeInstruction(SpvOpImageRead,
871 this->getType(c.fType),
872 result,
873 img,
874 coords,
875 SpvImageOperandsSampleMask,
876 sample,
877 out);
878 }
879 break;
880 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700881 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500882 SpvOp_ op = SpvOpImageSampleImplicitLod;
883 switch (c.fArguments[0]->fType.dimensions()) {
884 case SpvDim1D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400885 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500886 op = SpvOpImageSampleProjImplicitLod;
887 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400888 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500889 }
890 break;
891 case SpvDim2D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400892 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500893 op = SpvOpImageSampleProjImplicitLod;
894 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400895 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500896 }
897 break;
898 case SpvDim3D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400899 if (c.fArguments[1]->fType == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500900 op = SpvOpImageSampleProjImplicitLod;
901 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400902 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500903 }
904 break;
905 case SpvDimCube: // fall through
906 case SpvDimRect: // fall through
907 case SpvDimBuffer: // fall through
908 case SpvDimSubpassData:
909 break;
910 }
ethannicholasd598f792016-07-25 10:08:54 -0700911 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700912 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
913 SpvId uv = this->writeExpression(*c.fArguments[1], out);
914 if (c.fArguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500915 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700916 SpvImageOperandsBiasMask,
917 this->writeExpression(*c.fArguments[2], out),
918 out);
919 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400920 SkASSERT(c.fArguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500921 if (fProgram.fSettings.fSharpenTextures) {
922 FloatLiteral lodBias(fContext, -1, -0.5);
923 this->writeInstruction(op, type, result, sampler, uv,
924 SpvImageOperandsBiasMask,
925 this->writeFloatLiteral(lodBias),
926 out);
927 } else {
928 this->writeInstruction(op, type, result, sampler, uv,
929 out);
930 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700931 }
932 break;
933 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500934 case kMod_SpecialIntrinsic: {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500935 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400936 SkASSERT(args.size() == 2);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500937 const Type& operandType = c.fArguments[0]->fType;
938 SpvOp_ op;
939 if (is_float(fContext, operandType)) {
940 op = SpvOpFMod;
941 } else if (is_signed(fContext, operandType)) {
942 op = SpvOpSMod;
943 } else if (is_unsigned(fContext, operandType)) {
944 op = SpvOpUMod;
945 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400946 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500947 return 0;
948 }
949 this->writeOpCode(op, 5, out);
950 this->writeWord(this->getType(operandType), out);
951 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500952 this->writeWord(args[0], out);
953 this->writeWord(args[1], out);
954 break;
955 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700956 case kDFdy_SpecialIntrinsic: {
957 SpvId fn = this->writeExpression(*c.fArguments[0], out);
958 this->writeOpCode(SpvOpDPdy, 4, out);
959 this->writeWord(this->getType(c.fType), out);
960 this->writeWord(result, out);
961 this->writeWord(fn, out);
962 if (fProgram.fSettings.fFlipY) {
963 // Flipping Y also negates the Y derivatives.
964 SpvId flipped = this->nextId();
965 this->writeInstruction(SpvOpFNegate, this->getType(c.fType), flipped, result, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -0400966 this->writePrecisionModifier(c.fType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700967 return flipped;
968 }
969 break;
970 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500971 case kClamp_SpecialIntrinsic: {
972 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400973 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500974 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
975 GLSLstd450UClamp, args, out);
976 break;
977 }
978 case kMax_SpecialIntrinsic: {
979 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400980 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500981 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMax, GLSLstd450SMax,
982 GLSLstd450UMax, args, out);
983 break;
984 }
985 case kMin_SpecialIntrinsic: {
986 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400987 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500988 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMin, GLSLstd450SMin,
989 GLSLstd450UMin, args, out);
990 break;
991 }
992 case kMix_SpecialIntrinsic: {
993 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400994 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500995 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMix, SpvOpUndef,
996 SpvOpUndef, args, out);
997 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500998 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400999 case kSaturate_SpecialIntrinsic: {
1000 SkASSERT(c.fArguments.size() == 1);
1001 std::vector<std::unique_ptr<Expression>> finalArgs;
1002 finalArgs.push_back(c.fArguments[0]->clone());
1003 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 0));
1004 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 1));
1005 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
1006 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
1007 GLSLstd450UClamp, spvArgs, out);
1008 break;
1009 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001010 }
1011 return result;
1012}
1013
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001014SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001015 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07001016 if (entry == fFunctionMap.end()) {
1017 return this->writeIntrinsicCall(c, out);
1018 }
1019 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001020 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
ethannicholasb3058bd2016-07-01 08:22:01 -07001021 std::vector<SpvId> arguments;
1022 for (size_t i = 0; i < c.fArguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001023 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001024 // passed directly
1025 SpvId tmpVar;
1026 // if we need a temporary var to store this argument, this is the value to store in the var
1027 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -07001028 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001029 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
1030 SpvId ptr = lv->getPointer();
1031 if (ptr) {
1032 arguments.push_back(ptr);
1033 continue;
1034 } else {
1035 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1036 // copy it into a temp, call the function, read the value out of the temp, and then
1037 // update the lvalue.
1038 tmpValueId = lv->load(out);
1039 tmpVar = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001040 lvalues.push_back(std::make_tuple(tmpVar, &c.fArguments[i]->fType, std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001041 }
1042 } else {
1043 // see getFunctionType for an explanation of why we're always using pointer parameters
1044 tmpValueId = this->writeExpression(*c.fArguments[i], out);
1045 tmpVar = this->nextId();
1046 }
Greg Daniel64773e62016-11-22 09:44:03 -05001047 this->writeInstruction(SpvOpVariable,
1048 this->getPointerType(c.fArguments[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -07001049 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001050 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001051 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001052 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001053 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1054 arguments.push_back(tmpVar);
1055 }
1056 SpvId result = this->nextId();
1057 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001058 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001059 this->writeWord(result, out);
1060 this->writeWord(entry->second, out);
1061 for (SpvId id : arguments) {
1062 this->writeWord(id, out);
1063 }
1064 // now that the call is complete, we may need to update some lvalues with the new values of out
1065 // arguments
1066 for (const auto& tuple : lvalues) {
1067 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001068 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1069 out);
1070 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001071 std::get<2>(tuple)->store(load, out);
1072 }
1073 return result;
1074}
1075
ethannicholasf789b382016-08-03 12:43:36 -07001076SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001077 SkASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001078 SpvId result = this->nextId();
1079 std::vector<SpvId> arguments;
1080 for (size_t i = 0; i < c.fArguments.size(); i++) {
1081 arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1082 }
ethannicholasd598f792016-07-25 10:08:54 -07001083 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001084 if (c.fArguments.size() == 1) {
1085 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001086 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001087 this->writeWord(type, fConstantBuffer);
1088 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001089 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001090 this->writeWord(arguments[0], fConstantBuffer);
1091 }
1092 } else {
Greg Daniel64773e62016-11-22 09:44:03 -05001093 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001094 fConstantBuffer);
1095 this->writeWord(type, fConstantBuffer);
1096 this->writeWord(result, fConstantBuffer);
1097 for (SpvId id : arguments) {
1098 this->writeWord(id, fConstantBuffer);
1099 }
1100 }
1101 return result;
1102}
1103
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001104SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001105 SkASSERT(c.fType.isFloat());
1106 SkASSERT(c.fArguments.size() == 1);
1107 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001108 SpvId result = this->nextId();
1109 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001110 if (c.fArguments[0]->fType.isSigned()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001111 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001112 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001113 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001114 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Greg Daniel64773e62016-11-22 09:44:03 -05001115 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001116 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001117 }
1118 return result;
1119}
1120
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001121SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001122 SkASSERT(c.fType.isSigned());
1123 SkASSERT(c.fArguments.size() == 1);
1124 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001125 SpvId result = this->nextId();
1126 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001127 if (c.fArguments[0]->fType.isFloat()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001128 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001129 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001130 }
1131 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001132 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001133 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001134 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001135 }
1136 return result;
1137}
1138
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001139SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001140 SkASSERT(c.fType.isUnsigned());
1141 SkASSERT(c.fArguments.size() == 1);
1142 SkASSERT(c.fArguments[0]->fType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001143 SpvId result = this->nextId();
1144 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001145 if (c.fArguments[0]->fType.isFloat()) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001146 this->writeInstruction(SpvOpConvertFToU, this->getType(c.fType), result, parameter,
1147 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001148 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001149 SkASSERT(c.fArguments[0]->fType.isSigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001150 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
1151 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001152 }
1153 return result;
1154}
1155
Ethan Nicholas84645e32017-02-09 13:57:14 -05001156void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001157 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001158 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001159 SpvId zeroId = this->writeFloatLiteral(zero);
1160 std::vector<SpvId> columnIds;
1161 for (int column = 0; column < type.columns(); column++) {
1162 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1163 out);
1164 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1165 out);
1166 SpvId columnId = this->nextId();
1167 this->writeWord(columnId, out);
1168 columnIds.push_back(columnId);
1169 for (int row = 0; row < type.columns(); row++) {
1170 this->writeWord(row == column ? diagonal : zeroId, out);
1171 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001172 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001173 }
1174 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1175 out);
1176 this->writeWord(this->getType(type), out);
1177 this->writeWord(id, out);
1178 for (SpvId id : columnIds) {
1179 this->writeWord(id, out);
1180 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001181 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001182}
1183
1184void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001185 const Type& dstType, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001186 SkASSERT(srcType.kind() == Type::kMatrix_Kind);
1187 SkASSERT(dstType.kind() == Type::kMatrix_Kind);
1188 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001189 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1190 srcType.rows(),
1191 1));
1192 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1193 dstType.rows(),
1194 1));
1195 SpvId zeroId;
1196 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001197 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001198 zeroId = this->writeFloatLiteral(zero);
1199 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001200 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001201 zeroId = this->writeIntLiteral(zero);
1202 } else {
1203 ABORT("unsupported matrix component type");
1204 }
1205 SpvId zeroColumn = 0;
1206 SpvId columns[4];
1207 for (int i = 0; i < dstType.columns(); i++) {
1208 if (i < srcType.columns()) {
1209 // we're still inside the src matrix, copy the column
1210 SpvId srcColumn = this->nextId();
1211 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001212 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001213 SpvId dstColumn;
1214 if (srcType.rows() == dstType.rows()) {
1215 // columns are equal size, don't need to do anything
1216 dstColumn = srcColumn;
1217 }
1218 else if (dstType.rows() > srcType.rows()) {
1219 // dst column is bigger, need to zero-pad it
1220 dstColumn = this->nextId();
1221 int delta = dstType.rows() - srcType.rows();
1222 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1223 this->writeWord(dstColumnType, out);
1224 this->writeWord(dstColumn, out);
1225 this->writeWord(srcColumn, out);
1226 for (int i = 0; i < delta; ++i) {
1227 this->writeWord(zeroId, out);
1228 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001229 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001230 }
1231 else {
1232 // dst column is smaller, need to swizzle the src column
1233 dstColumn = this->nextId();
1234 int count = dstType.rows();
1235 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1236 this->writeWord(dstColumnType, out);
1237 this->writeWord(dstColumn, out);
1238 this->writeWord(srcColumn, out);
1239 this->writeWord(srcColumn, out);
1240 for (int i = 0; i < count; i++) {
1241 this->writeWord(i, out);
1242 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001243 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001244 }
1245 columns[i] = dstColumn;
1246 } else {
1247 // we're past the end of the src matrix, need a vector of zeroes
1248 if (!zeroColumn) {
1249 zeroColumn = this->nextId();
1250 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1251 this->writeWord(dstColumnType, out);
1252 this->writeWord(zeroColumn, out);
1253 for (int i = 0; i < dstType.rows(); ++i) {
1254 this->writeWord(zeroId, out);
1255 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001256 this->writePrecisionModifier(dstType, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001257 }
1258 columns[i] = zeroColumn;
1259 }
1260 }
1261 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1262 this->writeWord(this->getType(dstType), out);
1263 this->writeWord(id, out);
1264 for (int i = 0; i < dstType.columns(); i++) {
1265 this->writeWord(columns[i], out);
1266 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001267 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001268}
1269
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001270void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1271 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001272 std::vector<SpvId>* columnIds,
1273 int* currentCount, int rows, SpvId entry,
1274 OutputStream& out) {
1275 SkASSERT(*currentCount < rows);
1276 ++(*currentCount);
1277 currentColumn->push_back(entry);
1278 if (*currentCount == rows) {
1279 *currentCount = 0;
1280 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1281 this->writeWord(columnType, out);
1282 SpvId columnId = this->nextId();
1283 this->writeWord(columnId, out);
1284 columnIds->push_back(columnId);
1285 for (SpvId id : *currentColumn) {
1286 this->writeWord(id, out);
1287 }
1288 currentColumn->clear();
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001289 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001290 }
1291}
1292
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001293SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001294 SkASSERT(c.fType.kind() == Type::kMatrix_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001295 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1296 // an instruction
1297 std::vector<SpvId> arguments;
1298 for (size_t i = 0; i < c.fArguments.size(); i++) {
1299 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1300 }
1301 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001302 int rows = c.fType.rows();
1303 int columns = c.fType.columns();
Ethan Nicholas84645e32017-02-09 13:57:14 -05001304 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1305 this->writeUniformScaleMatrix(result, arguments[0], c.fType, out);
1306 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kMatrix_Kind) {
1307 this->writeMatrixCopy(result, arguments[0], c.fArguments[0]->fType, c.fType, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001308 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kVector_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001309 SkASSERT(c.fType.rows() == 2 && c.fType.columns() == 2);
1310 SkASSERT(c.fArguments[0]->fType.columns() == 4);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001311 SpvId componentType = this->getType(c.fType.componentType());
1312 SpvId v[4];
1313 for (int i = 0; i < 4; ++i) {
1314 v[i] = this->nextId();
1315 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i, out);
1316 }
1317 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, 2, 1));
1318 SpvId column1 = this->nextId();
1319 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1320 SpvId column2 = this->nextId();
1321 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
1322 this->writeInstruction(SpvOpCompositeConstruct, this->getType(c.fType), result, column1,
1323 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001324 } else {
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001325 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001326 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001327 // ids of vectors and scalars we have written to the current column so far
1328 std::vector<SpvId> currentColumn;
1329 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001330 int currentCount = 0;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001331 Precision precision = c.fType.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001332 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001333 if (currentCount == 0 && c.fArguments[i]->fType.kind() == Type::kVector_Kind &&
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001334 c.fArguments[i]->fType.columns() == c.fType.rows()) {
1335 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001336 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001337 } else {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001338 if (c.fArguments[i]->fType.columns() == 1) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001339 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1340 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001341 } else {
1342 SpvId componentType = this->getType(c.fArguments[i]->fType.componentType());
Ethan Nicholas811b9442018-05-11 13:16:03 -04001343 for (int j = 0; j < c.fArguments[i]->fType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001344 SpvId swizzle = this->nextId();
1345 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1346 arguments[i], j, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001347 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1348 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001349 }
1350 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001351 }
1352 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001353 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001354 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001355 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001356 this->writeWord(result, out);
1357 for (SpvId id : columnIds) {
1358 this->writeWord(id, out);
1359 }
1360 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001361 this->writePrecisionModifier(c.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001362 return result;
1363}
1364
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001365SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001366 SkASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001367 if (c.isConstant()) {
1368 return this->writeConstantVector(c);
1369 }
1370 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1371 // an instruction
1372 std::vector<SpvId> arguments;
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001373 for (size_t i = 0; i < c.fArguments.size(); i++) {
1374 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
1375 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1376 // extract the components and convert them in that case manually. On top of that,
1377 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1378 // doesn't handle vector arguments at all, so we always extract vector components and
1379 // pass them into OpCreateComposite individually.
1380 SpvId vec = this->writeExpression(*c.fArguments[i], out);
1381 SpvOp_ op = SpvOpUndef;
1382 const Type& src = c.fArguments[i]->fType.componentType();
1383 const Type& dst = c.fType.componentType();
1384 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1385 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1386 if (c.fArguments.size() == 1) {
1387 return vec;
1388 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001389 } else if (src == *fContext.fInt_Type ||
1390 src == *fContext.fShort_Type ||
1391 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001392 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001393 } else if (src == *fContext.fUInt_Type ||
1394 src == *fContext.fUShort_Type ||
1395 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001396 op = SpvOpConvertUToF;
1397 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001398 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001399 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001400 } else if (dst == *fContext.fInt_Type ||
1401 dst == *fContext.fShort_Type ||
1402 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001403 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1404 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001405 } else if (src == *fContext.fInt_Type ||
1406 src == *fContext.fShort_Type ||
1407 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001408 if (c.fArguments.size() == 1) {
1409 return vec;
1410 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001411 } else if (src == *fContext.fUInt_Type ||
1412 src == *fContext.fUShort_Type ||
1413 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001414 op = SpvOpBitcast;
1415 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001416 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001417 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001418 } else if (dst == *fContext.fUInt_Type ||
1419 dst == *fContext.fUShort_Type ||
1420 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001421 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1422 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001423 } else if (src == *fContext.fInt_Type ||
1424 src == *fContext.fShort_Type ||
1425 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001426 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001427 } else if (src == *fContext.fUInt_Type ||
1428 src == *fContext.fUShort_Type ||
1429 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001430 if (c.fArguments.size() == 1) {
1431 return vec;
1432 }
1433 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001434 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001435 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001436 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001437 for (int j = 0; j < c.fArguments[i]->fType.columns(); j++) {
1438 SpvId swizzle = this->nextId();
1439 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1440 out);
1441 if (op != SpvOpUndef) {
1442 SpvId cast = this->nextId();
1443 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1444 arguments.push_back(cast);
1445 } else {
1446 arguments.push_back(swizzle);
1447 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001448 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001449 } else {
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001450 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1451 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001452 }
1453 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001454 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1455 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1456 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001457 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001458 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001459 this->writeWord(arguments[0], out);
1460 }
1461 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001462 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001463 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001464 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001465 this->writeWord(result, out);
1466 for (SpvId id : arguments) {
1467 this->writeWord(id, out);
1468 }
1469 }
1470 return result;
1471}
1472
Ethan Nicholasbd553222017-07-18 15:54:59 -04001473SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001474 SkASSERT(c.fType.kind() == Type::kArray_Kind);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001475 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1476 // an instruction
1477 std::vector<SpvId> arguments;
1478 for (size_t i = 0; i < c.fArguments.size(); i++) {
1479 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1480 }
1481 SpvId result = this->nextId();
1482 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
1483 this->writeWord(this->getType(c.fType), out);
1484 this->writeWord(result, out);
1485 for (SpvId id : arguments) {
1486 this->writeWord(id, out);
1487 }
1488 return result;
1489}
1490
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001491SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001492 if (c.fArguments.size() == 1 &&
1493 this->getActualType(c.fType) == this->getActualType(c.fArguments[0]->fType)) {
1494 return this->writeExpression(*c.fArguments[0], out);
1495 }
1496 if (c.fType == *fContext.fFloat_Type || c.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001497 return this->writeFloatConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001498 } else if (c.fType == *fContext.fInt_Type ||
1499 c.fType == *fContext.fShort_Type ||
1500 c.fType == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001501 return this->writeIntConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001502 } else if (c.fType == *fContext.fUInt_Type ||
1503 c.fType == *fContext.fUShort_Type ||
1504 c.fType == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001505 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001506 }
ethannicholasd598f792016-07-25 10:08:54 -07001507 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001508 case Type::kVector_Kind:
1509 return this->writeVectorConstructor(c, out);
1510 case Type::kMatrix_Kind:
1511 return this->writeMatrixConstructor(c, out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001512 case Type::kArray_Kind:
1513 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001514 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001515#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07001516 ABORT("unsupported constructor: %s", c.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001517#endif
1518 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001519 }
1520}
1521
1522SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1523 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001524 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001525 return SpvStorageClassInput;
1526 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001527 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001528 return SpvStorageClassOutput;
1529 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001530 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001531 return SpvStorageClassPushConstant;
1532 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001533 return SpvStorageClassUniform;
1534 } else {
1535 return SpvStorageClassFunction;
1536 }
1537}
1538
ethannicholasf789b382016-08-03 12:43:36 -07001539SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001540 switch (expr.fKind) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001541 case Expression::kVariableReference_Kind: {
1542 const Variable& var = ((VariableReference&) expr).fVariable;
1543 if (var.fStorage != Variable::kGlobal_Storage) {
1544 return SpvStorageClassFunction;
1545 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001546 SpvStorageClass_ result = get_storage_class(var.fModifiers);
1547 if (result == SpvStorageClassFunction) {
1548 result = SpvStorageClassPrivate;
1549 }
1550 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001551 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001552 case Expression::kFieldAccess_Kind:
1553 return get_storage_class(*((FieldAccess&) expr).fBase);
1554 case Expression::kIndex_Kind:
1555 return get_storage_class(*((IndexExpression&) expr).fBase);
1556 default:
1557 return SpvStorageClassFunction;
1558 }
1559}
1560
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001561std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001562 std::vector<SpvId> chain;
1563 switch (expr.fKind) {
1564 case Expression::kIndex_Kind: {
1565 IndexExpression& indexExpr = (IndexExpression&) expr;
1566 chain = this->getAccessChain(*indexExpr.fBase, out);
1567 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1568 break;
1569 }
1570 case Expression::kFieldAccess_Kind: {
1571 FieldAccess& fieldExpr = (FieldAccess&) expr;
1572 chain = this->getAccessChain(*fieldExpr.fBase, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001573 IntLiteral index(fContext, -1, fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001574 chain.push_back(this->writeIntLiteral(index));
1575 break;
1576 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001577 default: {
1578 SpvId id = this->getLValue(expr, out)->getPointer();
1579 SkASSERT(id != 0);
1580 chain.push_back(id);
1581 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001582 }
1583 return chain;
1584}
1585
1586class PointerLValue : public SPIRVCodeGenerator::LValue {
1587public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001588 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1589 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001590 : fGen(gen)
1591 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001592 , fType(type)
1593 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001594
1595 virtual SpvId getPointer() override {
1596 return fPointer;
1597 }
1598
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001599 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001600 SpvId result = fGen.nextId();
1601 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001602 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001603 return result;
1604 }
1605
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001606 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001607 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1608 }
1609
1610private:
1611 SPIRVCodeGenerator& fGen;
1612 const SpvId fPointer;
1613 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001614 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001615};
1616
1617class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1618public:
Greg Daniel64773e62016-11-22 09:44:03 -05001619 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001620 const Type& baseType, const Type& swizzleType,
1621 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001622 : fGen(gen)
1623 , fVecPointer(vecPointer)
1624 , fComponents(components)
1625 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001626 , fSwizzleType(swizzleType)
1627 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001628
1629 virtual SpvId getPointer() override {
1630 return 0;
1631 }
1632
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001633 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001634 SpvId base = fGen.nextId();
1635 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001636 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001637 SpvId result = fGen.nextId();
1638 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1639 fGen.writeWord(fGen.getType(fSwizzleType), out);
1640 fGen.writeWord(result, out);
1641 fGen.writeWord(base, out);
1642 fGen.writeWord(base, out);
1643 for (int component : fComponents) {
1644 fGen.writeWord(component, out);
1645 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001646 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001647 return result;
1648 }
1649
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001650 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001651 // use OpVectorShuffle to mix and match the vector components. We effectively create
1652 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001653 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001654 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001655 // float3L = ...;
1656 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001657 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001658 // 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 -07001659 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1660 // (3, 1, 4).
1661 SpvId base = fGen.nextId();
1662 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1663 SpvId shuffle = fGen.nextId();
1664 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1665 fGen.writeWord(fGen.getType(fBaseType), out);
1666 fGen.writeWord(shuffle, out);
1667 fGen.writeWord(base, out);
1668 fGen.writeWord(value, out);
1669 for (int i = 0; i < fBaseType.columns(); i++) {
1670 // current offset into the virtual vector, defaults to pulling the unmodified
1671 // value from the left side
1672 int offset = i;
1673 // check to see if we are writing this component
1674 for (size_t j = 0; j < fComponents.size(); j++) {
1675 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001676 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001677 // the correct component of the right side instead of preserving the
1678 // value from the left
1679 offset = (int) (j + fBaseType.columns());
1680 break;
1681 }
1682 }
1683 fGen.writeWord(offset, out);
1684 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001685 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001686 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1687 }
1688
1689private:
1690 SPIRVCodeGenerator& fGen;
1691 const SpvId fVecPointer;
1692 const std::vector<int>& fComponents;
1693 const Type& fBaseType;
1694 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001695 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001696};
1697
Greg Daniel64773e62016-11-22 09:44:03 -05001698std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001699 OutputStream& out) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001700 Precision precision = expr.fType.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001701 switch (expr.fKind) {
1702 case Expression::kVariableReference_Kind: {
Ethan Nicholas5226b772018-05-03 16:20:41 -04001703 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07001704 const Variable& var = ((VariableReference&) expr).fVariable;
Ethan Nicholas5226b772018-05-03 16:20:41 -04001705 if (var.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
1706 type = this->getType(Type("sk_in", Type::kArray_Kind, var.fType.componentType(),
1707 fSkInCount));
1708 } else {
1709 type = this->getType(expr.fType);
1710 }
ethannicholasd598f792016-07-25 10:08:54 -07001711 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001712 SkASSERT(entry != fVariableMap.end());
Ethan Nicholas5226b772018-05-03 16:20:41 -04001713 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(*this,
1714 entry->second,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001715 type,
1716 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001717 }
1718 case Expression::kIndex_Kind: // fall through
1719 case Expression::kFieldAccess_Kind: {
1720 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1721 SpvId member = this->nextId();
1722 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001723 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001724 this->writeWord(member, out);
1725 for (SpvId idx : chain) {
1726 this->writeWord(idx, out);
1727 }
1728 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -04001729 *this,
1730 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001731 this->getType(expr.fType),
1732 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001733 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001734 case Expression::kSwizzle_Kind: {
1735 Swizzle& swizzle = (Swizzle&) expr;
1736 size_t count = swizzle.fComponents.size();
1737 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001738 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001739 if (count == 1) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001740 IntLiteral index(fContext, -1, swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001741 SpvId member = this->nextId();
1742 this->writeInstruction(SpvOpAccessChain,
Greg Daniel64773e62016-11-22 09:44:03 -05001743 this->getPointerType(swizzle.fType,
1744 get_storage_class(*swizzle.fBase)),
1745 member,
1746 base,
1747 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001748 out);
1749 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1750 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001751 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001752 this->getType(expr.fType),
1753 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001754 } else {
1755 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
Greg Daniel64773e62016-11-22 09:44:03 -05001756 *this,
1757 base,
1758 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001759 swizzle.fBase->fType,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001760 expr.fType,
1761 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001762 }
1763 }
Ethan Nicholasa583b812018-01-18 13:32:11 -05001764 case Expression::kTernary_Kind: {
1765 TernaryExpression& t = (TernaryExpression&) expr;
1766 SpvId test = this->writeExpression(*t.fTest, out);
1767 SpvId end = this->nextId();
1768 SpvId ifTrueLabel = this->nextId();
1769 SpvId ifFalseLabel = this->nextId();
1770 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1771 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1772 this->writeLabel(ifTrueLabel, out);
1773 SpvId ifTrue = this->getLValue(*t.fIfTrue, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001774 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001775 this->writeInstruction(SpvOpBranch, end, out);
1776 ifTrueLabel = fCurrentBlock;
1777 SpvId ifFalse = this->getLValue(*t.fIfFalse, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001778 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001779 ifFalseLabel = fCurrentBlock;
1780 this->writeInstruction(SpvOpBranch, end, out);
1781 SpvId result = this->nextId();
1782 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1783 ifTrueLabel, ifFalse, ifFalseLabel, out);
1784 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1785 *this,
1786 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001787 this->getType(expr.fType),
1788 precision));
Ethan Nicholasa583b812018-01-18 13:32:11 -05001789 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001790 default:
1791 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001792 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001793 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1794 // caught by IRGenerator
1795 SpvId result = this->nextId();
1796 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001797 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1798 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001799 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1800 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1801 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001802 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001803 this->getType(expr.fType),
1804 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001805 }
1806}
1807
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001808SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001809 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001810 auto entry = fVariableMap.find(&ref.fVariable);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001811 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001812 SpvId var = entry->second;
ethannicholasd598f792016-07-25 10:08:54 -07001813 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001814 this->writePrecisionModifier(ref.fVariable.fType, result);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001815 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
1816 fProgram.fSettings.fFlipY) {
1817 // need to remap to a top-left coordinate system
Greg Daniele6ab9982018-08-22 13:56:32 +00001818 if (fRTHeightStructId == (SpvId) -1) {
1819 // height variable hasn't been written yet
1820 std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors));
1821 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
1822 std::vector<Type::Field> fields;
Ethan Nicholas0be34802019-08-15 12:36:58 -04001823 SkASSERT(fProgram.fSettings.fRTHeightOffset >= 0);
1824 fields.emplace_back(Modifiers(Layout(0, -1, fProgram.fSettings.fRTHeightOffset, -1,
1825 -1, -1, -1, -1, Layout::Format::kUnspecified,
1826 Layout::kUnspecified_Primitive, -1, -1, "",
1827 Layout::kNo_Key, Layout::CType::kDefault), 0),
1828 SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
Greg Daniele6ab9982018-08-22 13:56:32 +00001829 StringFragment name("sksl_synthetic_uniforms");
1830 Type intfStruct(-1, name, fields);
Ethan Nicholas0be34802019-08-15 12:36:58 -04001831 int binding;
1832 int set;
1833#ifdef SK_VULKAN
1834 const GrVkCaps* vkCaps = fProgram.fSettings.fVkCaps;
1835 SkASSERT(vkCaps);
1836 binding = vkCaps->getFragmentUniformBinding();
1837 set = vkCaps->getFragmentUniformSet();
1838#else
1839 binding = 0;
1840 set = 0;
1841#endif
1842 Layout layout(0, -1, -1, binding, -1, set, -1, -1, Layout::Format::kUnspecified,
Greg Daniele6ab9982018-08-22 13:56:32 +00001843 Layout::kUnspecified_Primitive, -1, -1, "", Layout::kNo_Key,
Ethan Nicholas78aceb22018-08-31 16:13:58 -04001844 Layout::CType::kDefault);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001845 Variable* intfVar = (Variable*) fSynthetics.takeOwnership(std::unique_ptr<Symbol>(
1846 new Variable(-1,
1847 Modifiers(layout, Modifiers::kUniform_Flag),
1848 name,
1849 intfStruct,
1850 Variable::kGlobal_Storage)));
Greg Daniele6ab9982018-08-22 13:56:32 +00001851 InterfaceBlock intf(-1, intfVar, name, String(""),
1852 std::vector<std::unique_ptr<Expression>>(), st);
1853 fRTHeightStructId = this->writeInterfaceBlock(intf);
1854 fRTHeightFieldIndex = 0;
1855 }
1856 SkASSERT(fRTHeightFieldIndex != (SpvId) -1);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001857 // write float4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, gl_FragCoord.w)
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001858 SpvId xId = this->nextId();
1859 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1860 result, 0, out);
Greg Daniele6ab9982018-08-22 13:56:32 +00001861 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1862 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1863 SpvId heightPtr = this->nextId();
1864 this->writeOpCode(SpvOpAccessChain, 5, out);
1865 this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out);
1866 this->writeWord(heightPtr, out);
1867 this->writeWord(fRTHeightStructId, out);
1868 this->writeWord(fieldIndexId, out);
1869 SpvId heightRead = this->nextId();
1870 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1871 heightPtr, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001872 SpvId rawYId = this->nextId();
1873 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1874 result, 1, out);
1875 SpvId flippedYId = this->nextId();
1876 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
Greg Daniele6ab9982018-08-22 13:56:32 +00001877 heightRead, rawYId, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001878 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001879 SpvId zeroId = writeFloatLiteral(zero);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001880 FloatLiteral one(fContext, -1, 1.0);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001881 SpvId wId = this->nextId();
1882 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), wId,
1883 result, 3, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001884 SpvId flipped = this->nextId();
1885 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001886 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001887 this->writeWord(flipped, out);
1888 this->writeWord(xId, out);
1889 this->writeWord(flippedYId, out);
1890 this->writeWord(zeroId, out);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001891 this->writeWord(wId, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001892 return flipped;
1893 }
Chris Daltonb91c4662018-08-01 10:46:22 -06001894 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
1895 !fProgram.fSettings.fFlipY) {
1896 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1897 // the default convention of "counter-clockwise face is front".
1898 SpvId inverse = this->nextId();
1899 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1900 result, out);
1901 return inverse;
1902 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001903 return result;
1904}
1905
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001906SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001907 if (expr.fBase->fType.kind() == Type::Kind::kVector_Kind) {
1908 SpvId base = this->writeExpression(*expr.fBase, out);
1909 SpvId index = this->writeExpression(*expr.fIndex, out);
1910 SpvId result = this->nextId();
1911 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.fType), result, base,
1912 index, out);
1913 return result;
1914 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001915 return getLValue(expr, out)->load(out);
1916}
1917
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001918SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001919 return getLValue(f, out)->load(out);
1920}
1921
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001922SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001923 SpvId base = this->writeExpression(*swizzle.fBase, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001924 SpvId result = this->nextId();
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001925 size_t count = swizzle.fComponents.size();
ethannicholasb3058bd2016-07-01 08:22:01 -07001926 if (count == 1) {
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001927 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
1928 swizzle.fComponents[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001929 } else {
1930 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001931 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001932 this->writeWord(result, out);
1933 this->writeWord(base, out);
Ethan Nicholase455f652019-09-13 12:52:55 -04001934 SpvId other = base;
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001935 for (int c : swizzle.fComponents) {
Ethan Nicholase455f652019-09-13 12:52:55 -04001936 if (c < 0) {
1937 if (!fConstantZeroOneVector) {
1938 FloatLiteral zero(fContext, -1, 0);
1939 SpvId zeroId = this->writeFloatLiteral(zero);
1940 FloatLiteral one(fContext, -1, 1);
1941 SpvId oneId = this->writeFloatLiteral(one);
1942 SpvId type = this->getType(*fContext.fFloat2_Type);
1943 fConstantZeroOneVector = this->nextId();
1944 this->writeOpCode(SpvOpConstantComposite, 5, fConstantBuffer);
1945 this->writeWord(type, fConstantBuffer);
1946 this->writeWord(fConstantZeroOneVector, fConstantBuffer);
1947 this->writeWord(zeroId, fConstantBuffer);
1948 this->writeWord(oneId, fConstantBuffer);
1949 }
1950 other = fConstantZeroOneVector;
1951 break;
Ethan Nicholasac285b12019-02-12 16:05:18 -05001952 }
Ethan Nicholasac285b12019-02-12 16:05:18 -05001953 }
1954 this->writeWord(other, out);
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001955 for (int component : swizzle.fComponents) {
Ethan Nicholasac285b12019-02-12 16:05:18 -05001956 if (component == SKSL_SWIZZLE_0) {
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001957 this->writeWord(swizzle.fBase->fType.columns(), out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001958 } else if (component == SKSL_SWIZZLE_1) {
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001959 this->writeWord(swizzle.fBase->fType.columns() + 1, out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001960 } else {
1961 this->writeWord(component, out);
1962 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001963 }
1964 }
1965 return result;
1966}
1967
Greg Daniel64773e62016-11-22 09:44:03 -05001968SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1969 const Type& operandType, SpvId lhs,
1970 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001971 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001972 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001973 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001974 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001975 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001976 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001977 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001978 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001979 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001980 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001981 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07001982 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001983#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07001984 ABORT("invalid operandType: %s", operandType.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001985#endif
ethannicholasb3058bd2016-07-01 08:22:01 -07001986 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04001987 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001988 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
1989 fDecorationBuffer);
1990 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001991 return result;
1992}
1993
Ethan Nicholas48e24052018-03-14 13:51:39 -04001994SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
1995 OutputStream& out) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05001996 if (operandType.kind() == Type::kVector_Kind) {
1997 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001998 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05001999 return result;
2000 }
2001 return id;
2002}
2003
Ethan Nicholas68990be2017-07-13 09:36:52 -04002004SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
2005 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002006 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04002007 OutputStream& out) {
2008 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002009 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002010 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2011 operandType.rows(),
2012 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04002013 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002014 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04002015 1));
2016 SpvId boolType = this->getType(*fContext.fBool_Type);
2017 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04002018 for (int i = 0; i < operandType.columns(); i++) {
2019 SpvId columnL = this->nextId();
2020 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2021 SpvId columnR = this->nextId();
2022 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002023 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002024 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
2025 SpvId merge = this->nextId();
2026 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002027 if (result != 0) {
2028 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002029 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002030 result = next;
2031 }
2032 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002033 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04002034 }
2035 }
2036 return result;
2037}
2038
Ethan Nicholas0df21132018-07-10 09:37:51 -04002039SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
2040 SpvId rhs, SpvOp_ floatOperator,
2041 SpvOp_ intOperator,
2042 OutputStream& out) {
2043 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
2044 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
2045 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2046 operandType.rows(),
2047 1));
2048 SpvId columns[4];
2049 for (int i = 0; i < operandType.columns(); i++) {
2050 SpvId columnL = this->nextId();
2051 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2052 SpvId columnR = this->nextId();
2053 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2054 columns[i] = this->nextId();
2055 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2056 }
2057 SpvId result = this->nextId();
2058 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2059 this->writeWord(this->getType(operandType), out);
2060 this->writeWord(result, out);
2061 for (int i = 0; i < operandType.columns(); i++) {
2062 this->writeWord(columns[i], out);
2063 }
2064 return result;
2065}
2066
Ethan Nicholas49465b42019-04-17 12:22:21 -04002067std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2068 if (type.isInteger()) {
2069 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002070 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002071 else if (type.isFloat()) {
2072 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002073 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002074 ABORT("math is unsupported on type '%s'", type.name().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002075 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002076}
2077
2078SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Token::Kind op,
2079 const Type& rightType, SpvId rhs,
2080 const Type& resultType, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002081 Type tmp("<invalid>");
Ethan Nicholas48e24052018-03-14 13:51:39 -04002082 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002083 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002084 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2085 // handling in SPIR-V
Ethan Nicholas49465b42019-04-17 12:22:21 -04002086 if (this->getActualType(leftType) != this->getActualType(rightType)) {
2087 if (leftType.kind() == Type::kVector_Kind && rightType.isNumber()) {
2088 if (op == Token::SLASH) {
2089 SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
2090 SpvId inverse = this->nextId();
2091 this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
2092 rhs = inverse;
2093 op = Token::STAR;
2094 }
2095 if (op == Token::STAR) {
2096 SpvId result = this->nextId();
2097 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2098 result, lhs, rhs, out);
2099 return result;
2100 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002101 // promote number to vector
2102 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002103 const Type& vecType = leftType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002104 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2105 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002106 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002107 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002108 this->writeWord(rhs, out);
2109 }
2110 rhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002111 operandType = &leftType;
2112 } else if (rightType.kind() == Type::kVector_Kind && leftType.isNumber()) {
2113 if (op == Token::STAR) {
2114 SpvId result = this->nextId();
2115 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2116 result, rhs, lhs, out);
2117 return result;
2118 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002119 // promote number to vector
2120 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002121 const Type& vecType = rightType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002122 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2123 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002124 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002125 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002126 this->writeWord(lhs, out);
2127 }
2128 lhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002129 operandType = &rightType;
2130 } else if (leftType.kind() == Type::kMatrix_Kind) {
2131 SpvOp_ spvop;
2132 if (rightType.kind() == Type::kMatrix_Kind) {
2133 spvop = SpvOpMatrixTimesMatrix;
2134 } else if (rightType.kind() == Type::kVector_Kind) {
2135 spvop = SpvOpMatrixTimesVector;
ethannicholasb3058bd2016-07-01 08:22:01 -07002136 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002137 SkASSERT(rightType.kind() == Type::kScalar_Kind);
2138 spvop = SpvOpMatrixTimesScalar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002139 }
2140 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002141 this->writeInstruction(spvop, this->getType(resultType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002142 return result;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002143 } else if (rightType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002144 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002145 if (leftType.kind() == Type::kVector_Kind) {
2146 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(resultType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002147 lhs, rhs, out);
2148 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002149 SkASSERT(leftType.kind() == Type::kScalar_Kind);
2150 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(resultType), result,
2151 rhs, lhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002152 }
2153 return result;
2154 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002155 SkASSERT(false);
2156 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002157 }
2158 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002159 tmp = this->getActualType(leftType);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002160 operandType = &tmp;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002161 SkASSERT(*operandType == this->getActualType(rightType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002162 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002163 switch (op) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002164 case Token::EQEQ: {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002165 if (operandType->kind() == Type::kMatrix_Kind) {
2166 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002167 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002168 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002169 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002170 const Type* tmpType;
2171 if (operandType->kind() == Type::kVector_Kind) {
2172 tmpType = &fContext.fBool_Type->toCompound(fContext,
2173 operandType->columns(),
2174 operandType->rows());
2175 } else {
2176 tmpType = &resultType;
2177 }
2178 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002179 SpvOpFOrdEqual, SpvOpIEqual,
2180 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002181 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002182 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002183 case Token::NEQ:
Ethan Nicholas68990be2017-07-13 09:36:52 -04002184 if (operandType->kind() == Type::kMatrix_Kind) {
2185 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002186 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002187 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002188 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002189 const Type* tmpType;
2190 if (operandType->kind() == Type::kVector_Kind) {
2191 tmpType = &fContext.fBool_Type->toCompound(fContext,
2192 operandType->columns(),
2193 operandType->rows());
2194 } else {
2195 tmpType = &resultType;
2196 }
2197 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002198 SpvOpFOrdNotEqual, SpvOpINotEqual,
2199 SpvOpINotEqual, SpvOpLogicalNotEqual,
2200 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002201 *operandType, SpvOpAny, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002202 case Token::GT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002203 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002204 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2205 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002206 SpvOpUGreaterThan, SpvOpUndef, out);
2207 case Token::LT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002208 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002209 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002210 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
2211 case Token::GTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002212 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002213 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2214 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002215 SpvOpUGreaterThanEqual, SpvOpUndef, out);
2216 case Token::LTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002217 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002218 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2219 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002220 SpvOpULessThanEqual, SpvOpUndef, out);
2221 case Token::PLUS:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002222 if (leftType.kind() == Type::kMatrix_Kind &&
2223 rightType.kind() == Type::kMatrix_Kind) {
2224 SkASSERT(leftType == rightType);
2225 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002226 SpvOpFAdd, SpvOpIAdd, out);
2227 }
Greg Daniel64773e62016-11-22 09:44:03 -05002228 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002229 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2230 case Token::MINUS:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002231 if (leftType.kind() == Type::kMatrix_Kind &&
2232 rightType.kind() == Type::kMatrix_Kind) {
2233 SkASSERT(leftType == rightType);
2234 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002235 SpvOpFSub, SpvOpISub, out);
2236 }
Greg Daniel64773e62016-11-22 09:44:03 -05002237 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002238 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2239 case Token::STAR:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002240 if (leftType.kind() == Type::kMatrix_Kind &&
2241 rightType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002242 // matrix multiply
2243 SpvId result = this->nextId();
2244 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2245 lhs, rhs, out);
2246 return result;
2247 }
Greg Daniel64773e62016-11-22 09:44:03 -05002248 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002249 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2250 case Token::SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002251 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002252 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002253 case Token::PERCENT:
2254 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2255 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002256 case Token::SHL:
2257 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2258 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2259 SpvOpUndef, out);
2260 case Token::SHR:
2261 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2262 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2263 SpvOpUndef, out);
2264 case Token::BITWISEAND:
2265 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2266 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
2267 case Token::BITWISEOR:
2268 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2269 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
2270 case Token::BITWISEXOR:
2271 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2272 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04002273 case Token::COMMA:
2274 return rhs;
ethannicholasb3058bd2016-07-01 08:22:01 -07002275 default:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002276 SkASSERT(false);
2277 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002278 }
2279}
2280
Ethan Nicholas49465b42019-04-17 12:22:21 -04002281SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
2282 // handle cases where we don't necessarily evaluate both LHS and RHS
2283 switch (b.fOperator) {
2284 case Token::EQ: {
2285 SpvId rhs = this->writeExpression(*b.fRight, out);
2286 this->getLValue(*b.fLeft, out)->store(rhs, out);
2287 return rhs;
2288 }
2289 case Token::LOGICALAND:
2290 return this->writeLogicalAnd(b, out);
2291 case Token::LOGICALOR:
2292 return this->writeLogicalOr(b, out);
2293 default:
2294 break;
2295 }
2296
2297 std::unique_ptr<LValue> lvalue;
2298 SpvId lhs;
2299 if (is_assignment(b.fOperator)) {
2300 lvalue = this->getLValue(*b.fLeft, out);
2301 lhs = lvalue->load(out);
2302 } else {
2303 lvalue = nullptr;
2304 lhs = this->writeExpression(*b.fLeft, out);
2305 }
2306 SpvId rhs = this->writeExpression(*b.fRight, out);
2307 SpvId result = this->writeBinaryExpression(b.fLeft->fType, lhs, remove_assignment(b.fOperator),
2308 b.fRight->fType, rhs, b.fType, out);
2309 if (lvalue) {
2310 lvalue->store(result, out);
2311 }
2312 return result;
2313}
2314
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002315SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002316 SkASSERT(a.fOperator == Token::LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002317 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002318 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2319 SpvId lhs = this->writeExpression(*a.fLeft, out);
2320 SpvId rhsLabel = this->nextId();
2321 SpvId end = this->nextId();
2322 SpvId lhsBlock = fCurrentBlock;
2323 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2324 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2325 this->writeLabel(rhsLabel, out);
2326 SpvId rhs = this->writeExpression(*a.fRight, out);
2327 SpvId rhsBlock = fCurrentBlock;
2328 this->writeInstruction(SpvOpBranch, end, out);
2329 this->writeLabel(end, out);
2330 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002331 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002332 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002333 return result;
2334}
2335
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002336SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002337 SkASSERT(o.fOperator == Token::LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002338 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002339 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2340 SpvId lhs = this->writeExpression(*o.fLeft, out);
2341 SpvId rhsLabel = this->nextId();
2342 SpvId end = this->nextId();
2343 SpvId lhsBlock = fCurrentBlock;
2344 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2345 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2346 this->writeLabel(rhsLabel, out);
2347 SpvId rhs = this->writeExpression(*o.fRight, out);
2348 SpvId rhsBlock = fCurrentBlock;
2349 this->writeInstruction(SpvOpBranch, end, out);
2350 this->writeLabel(end, out);
2351 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002352 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002353 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002354 return result;
2355}
2356
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002357SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002358 SpvId test = this->writeExpression(*t.fTest, out);
Ethan Nicholas0f21c232018-07-23 09:25:40 -04002359 if (t.fIfTrue->fType.columns() == 1 && t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002360 // both true and false are constants, can just use OpSelect
2361 SpvId result = this->nextId();
2362 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2363 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
Greg Daniel64773e62016-11-22 09:44:03 -05002364 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002365 out);
2366 return result;
2367 }
Greg Daniel64773e62016-11-22 09:44:03 -05002368 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002369 // Adreno. Switched to storing the result in a temp variable as glslang does.
2370 SpvId var = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002371 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002372 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002373 SpvId trueLabel = this->nextId();
2374 SpvId falseLabel = this->nextId();
2375 SpvId end = this->nextId();
2376 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2377 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2378 this->writeLabel(trueLabel, out);
2379 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2380 this->writeInstruction(SpvOpBranch, end, out);
2381 this->writeLabel(falseLabel, out);
2382 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2383 this->writeInstruction(SpvOpBranch, end, out);
2384 this->writeLabel(end, out);
2385 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002386 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002387 this->writePrecisionModifier(t.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002388 return result;
2389}
2390
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002391SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002392 if (p.fOperator == Token::MINUS) {
2393 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002394 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002395 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002396 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002397 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002398 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002399 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2400 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002401#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002402 ABORT("unsupported prefix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002403#endif
Brian Salomon23356442018-11-30 15:33:19 -05002404 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002405 this->writePrecisionModifier(p.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002406 return result;
2407 }
2408 switch (p.fOperator) {
2409 case Token::PLUS:
2410 return this->writeExpression(*p.fOperand, out);
2411 case Token::PLUSPLUS: {
2412 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002413 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002414 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2415 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002416 out);
2417 lv->store(result, out);
2418 return result;
2419 }
2420 case Token::MINUSMINUS: {
2421 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002422 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002423 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2424 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002425 out);
2426 lv->store(result, out);
2427 return result;
2428 }
ethannicholas5961bc92016-10-12 06:39:56 -07002429 case Token::LOGICALNOT: {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002430 SkASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002431 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002432 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002433 this->writeExpression(*p.fOperand, out), out);
2434 return result;
2435 }
ethannicholas5961bc92016-10-12 06:39:56 -07002436 case Token::BITWISENOT: {
2437 SpvId result = this->nextId();
2438 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2439 this->writeExpression(*p.fOperand, out), out);
2440 return result;
2441 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002442 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002443#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002444 ABORT("unsupported prefix expression: %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002445#endif
2446 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002447 }
2448}
2449
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002450SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002451 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2452 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002453 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002454 switch (p.fOperator) {
2455 case Token::PLUSPLUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002456 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002457 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2458 lv->store(temp, out);
2459 return result;
2460 }
2461 case Token::MINUSMINUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002462 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002463 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2464 lv->store(temp, out);
2465 return result;
2466 }
2467 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002468#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002469 ABORT("unsupported postfix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002470#endif
2471 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002472 }
2473}
2474
ethannicholasf789b382016-08-03 12:43:36 -07002475SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002476 if (b.fValue) {
2477 if (fBoolTrue == 0) {
2478 fBoolTrue = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002479 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002480 fConstantBuffer);
2481 }
2482 return fBoolTrue;
2483 } else {
2484 if (fBoolFalse == 0) {
2485 fBoolFalse = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002486 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002487 fConstantBuffer);
2488 }
2489 return fBoolFalse;
2490 }
2491}
2492
ethannicholasf789b382016-08-03 12:43:36 -07002493SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002494 ConstantType type;
ethannicholasd598f792016-07-25 10:08:54 -07002495 if (i.fType == *fContext.fInt_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002496 type = ConstantType::kInt;
2497 } else if (i.fType == *fContext.fUInt_Type) {
2498 type = ConstantType::kUInt;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002499 } else if (i.fType == *fContext.fShort_Type || i.fType == *fContext.fByte_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002500 type = ConstantType::kShort;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002501 } else if (i.fType == *fContext.fUShort_Type || i.fType == *fContext.fUByte_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002502 type = ConstantType::kUShort;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002503 } else {
2504 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002505 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002506 std::pair<ConstantValue, ConstantType> key(i.fValue, type);
2507 auto entry = fNumberConstants.find(key);
2508 if (entry == fNumberConstants.end()) {
2509 SpvId result = this->nextId();
2510 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
2511 fConstantBuffer);
2512 fNumberConstants[key] = result;
2513 return result;
2514 }
2515 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002516}
2517
ethannicholasf789b382016-08-03 12:43:36 -07002518SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholase1f55022019-02-05 17:17:40 -05002519 if (f.fType != *fContext.fDouble_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002520 ConstantType type;
2521 if (f.fType == *fContext.fHalf_Type) {
2522 type = ConstantType::kHalf;
2523 } else {
2524 type = ConstantType::kFloat;
2525 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002526 float value = (float) f.fValue;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002527 std::pair<ConstantValue, ConstantType> key(f.fValue, type);
2528 auto entry = fNumberConstants.find(key);
2529 if (entry == fNumberConstants.end()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002530 SpvId result = this->nextId();
2531 uint32_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002532 SkASSERT(sizeof(bits) == sizeof(value));
ethannicholasb3058bd2016-07-01 08:22:01 -07002533 memcpy(&bits, &value, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002534 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
ethannicholasb3058bd2016-07-01 08:22:01 -07002535 fConstantBuffer);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002536 fNumberConstants[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002537 return result;
2538 }
2539 return entry->second;
2540 } else {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002541 std::pair<ConstantValue, ConstantType> key(f.fValue, ConstantType::kDouble);
2542 auto entry = fNumberConstants.find(key);
2543 if (entry == fNumberConstants.end()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002544 SpvId result = this->nextId();
2545 uint64_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002546 SkASSERT(sizeof(bits) == sizeof(f.fValue));
ethannicholasb3058bd2016-07-01 08:22:01 -07002547 memcpy(&bits, &f.fValue, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002548 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002549 bits & 0xffffffff, bits >> 32, fConstantBuffer);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002550 fNumberConstants[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002551 return result;
2552 }
2553 return entry->second;
2554 }
2555}
2556
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002557SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002558 SpvId result = fFunctionMap[&f];
Greg Daniel64773e62016-11-22 09:44:03 -05002559 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002560 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002561 this->writeInstruction(SpvOpName, result, f.fName, fNameBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002562 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002563 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002564 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002565 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002566 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002567 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2568 }
2569 return result;
2570}
2571
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002572SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2573 fVariableBuffer.reset();
ethannicholasb3058bd2016-07-01 08:22:01 -07002574 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2575 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002576 StringStream bodyBuffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04002577 this->writeBlock((Block&) *f.fBody, bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002578 write_stringstream(fVariableBuffer, out);
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002579 if (f.fDeclaration.fName == "main") {
2580 write_stringstream(fGlobalInitializersBuffer, out);
2581 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002582 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002583 if (fCurrentBlock) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002584 if (f.fDeclaration.fReturnType == *fContext.fVoid_Type) {
2585 this->writeInstruction(SpvOpReturn, out);
2586 } else {
2587 this->writeInstruction(SpvOpUnreachable, out);
2588 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002589 }
2590 this->writeInstruction(SpvOpFunctionEnd, out);
2591 return result;
2592}
2593
2594void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2595 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002596 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002597 fDecorationBuffer);
2598 }
2599 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002600 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002601 fDecorationBuffer);
2602 }
2603 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002604 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002605 fDecorationBuffer);
2606 }
2607 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002608 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002609 fDecorationBuffer);
2610 }
Greg Daniel64773e62016-11-22 09:44:03 -05002611 if (layout.fInputAttachmentIndex >= 0) {
2612 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2613 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002614 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002615 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002616 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002617 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002618 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002619 fDecorationBuffer);
2620 }
2621}
2622
2623void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2624 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002625 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002626 layout.fLocation, fDecorationBuffer);
2627 }
2628 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002629 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002630 layout.fBinding, fDecorationBuffer);
2631 }
2632 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002633 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002634 layout.fIndex, fDecorationBuffer);
2635 }
2636 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002637 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002638 layout.fSet, fDecorationBuffer);
2639 }
Greg Daniel64773e62016-11-22 09:44:03 -05002640 if (layout.fInputAttachmentIndex >= 0) {
2641 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2642 layout.fInputAttachmentIndex, fDecorationBuffer);
2643 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002644 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002645 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002646 layout.fBuiltin, fDecorationBuffer);
2647 }
2648}
2649
Ethan Nicholas81d15112018-07-13 12:48:50 -04002650static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2651 switch (m.fLayout.fPrimitive) {
2652 case Layout::kPoints_Primitive:
2653 *outSkInCount = 1;
2654 break;
2655 case Layout::kLines_Primitive:
2656 *outSkInCount = 2;
2657 break;
2658 case Layout::kLinesAdjacency_Primitive:
2659 *outSkInCount = 4;
2660 break;
2661 case Layout::kTriangles_Primitive:
2662 *outSkInCount = 3;
2663 break;
2664 case Layout::kTrianglesAdjacency_Primitive:
2665 *outSkInCount = 6;
2666 break;
2667 default:
2668 return;
2669 }
2670}
2671
ethannicholasf789b382016-08-03 12:43:36 -07002672SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas361941e2017-05-30 15:41:07 -04002673 bool isBuffer = (0 != (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag));
Ethan Nicholas39204fd2017-11-27 13:12:30 -05002674 bool pushConstant = (0 != (intf.fVariable.fModifiers.fLayout.fFlags &
2675 Layout::kPushConstant_Flag));
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002676 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2677 MemoryLayout(MemoryLayout::k430_Standard) :
2678 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002679 SpvId result = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002680 const Type* type = &intf.fVariable.fType;
Greg Daniele6ab9982018-08-22 13:56:32 +00002681 if (fProgram.fInputs.fRTHeight) {
2682 SkASSERT(fRTHeightStructId == (SpvId) -1);
2683 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002684 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002685 fRTHeightStructId = result;
2686 fRTHeightFieldIndex = fields.size();
2687 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002688 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002689 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002690 SpvId typeId;
2691 if (intf.fVariable.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2692 for (const auto& e : fProgram) {
2693 if (e.fKind == ProgramElement::kModifiers_Kind) {
2694 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholas81d15112018-07-13 12:48:50 -04002695 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002696 }
2697 }
2698 typeId = this->getType(Type("sk_in", Type::kArray_Kind, intf.fVariable.fType.componentType(),
2699 fSkInCount), memoryLayout);
2700 } else {
2701 typeId = this->getType(*type, memoryLayout);
2702 }
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002703 if (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag) {
2704 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002705 } else if (intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
2706 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002707 }
ethannicholasd598f792016-07-25 10:08:54 -07002708 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002709 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002710 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002711 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002712 Layout layout = intf.fVariable.fModifiers.fLayout;
2713 if (intf.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
2714 layout.fSet = 0;
2715 }
2716 this->writeLayout(layout, result);
ethannicholasd598f792016-07-25 10:08:54 -07002717 fVariableMap[&intf.fVariable] = result;
Greg Daniele6ab9982018-08-22 13:56:32 +00002718 if (fProgram.fInputs.fRTHeight) {
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002719 delete type;
2720 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002721 return result;
2722}
2723
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002724void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002725 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2726}
2727
2728void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2729 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002730 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2731 }
2732}
2733
Chris Dalton2284aab2019-11-15 11:02:24 -07002734bool is_dead(const Variable& var) {
2735 if (var.fReadCount || var.fWriteCount) {
2736 return false;
2737 }
2738 // not entirely sure what the rules are for when it's safe to elide interface variables, but it
2739 // causes various problems to elide some of them even when dead. But it also causes problems
2740 // *not* to elide sk_SampleMask when it's not being used.
2741 if (!(var.fModifiers.fFlags & (Modifiers::kIn_Flag |
2742 Modifiers::kOut_Flag |
2743 Modifiers::kUniform_Flag |
2744 Modifiers::kBuffer_Flag))) {
2745 return true;
2746 }
2747 return var.fModifiers.fLayout.fBuiltin == SK_SAMPLEMASK_BUILTIN;
2748}
2749
ethannicholas5961bc92016-10-12 06:39:56 -07002750#define BUILTIN_IGNORE 9999
Greg Daniel64773e62016-11-22 09:44:03 -05002751void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002752 OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002753 for (size_t i = 0; i < decl.fVars.size(); i++) {
2754 if (decl.fVars[i]->fKind == Statement::kNop_Kind) {
2755 continue;
2756 }
2757 const VarDeclaration& varDecl = (VarDeclaration&) *decl.fVars[i];
2758 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002759 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2760 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002761 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Chris Daltonb0fd4b12019-10-29 13:41:22 -06002762 Modifiers::kWriteOnly_Flag |
2763 Modifiers::kCoherent_Flag |
2764 Modifiers::kVolatile_Flag |
2765 Modifiers::kRestrict_Flag)));
ethannicholas5961bc92016-10-12 06:39:56 -07002766 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2767 continue;
2768 }
2769 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2770 kind != Program::kFragment_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002771 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
ethannicholas5961bc92016-10-12 06:39:56 -07002772 continue;
2773 }
Chris Dalton2284aab2019-11-15 11:02:24 -07002774 if (is_dead(*var)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002775 continue;
2776 }
2777 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002778 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002779 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002780 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002781 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002782 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
Stephen Whiteff5d7a22019-07-26 17:42:06 -04002783 if (var->fType.kind() == Type::kSampler_Kind ||
2784 var->fType.kind() == Type::kSeparateSampler_Kind ||
2785 var->fType.kind() == Type::kTexture_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002786 storageClass = SpvStorageClassUniformConstant;
2787 } else {
2788 storageClass = SpvStorageClassUniform;
2789 }
2790 } else {
2791 storageClass = SpvStorageClassPrivate;
2792 }
2793 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002794 fVariableMap[var] = id;
Ethan Nicholas5226b772018-05-03 16:20:41 -04002795 SpvId type;
2796 if (var->fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2797 type = this->getPointerType(Type("sk_in", Type::kArray_Kind,
2798 var->fType.componentType(), fSkInCount),
2799 storageClass);
2800 } else {
2801 type = this->getPointerType(var->fType, storageClass);
2802 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002803 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002804 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002805 this->writePrecisionModifier(var->fType, id);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002806 if (varDecl.fValue) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002807 SkASSERT(!fCurrentBlock);
ethannicholasf789b382016-08-03 12:43:36 -07002808 fCurrentBlock = -1;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002809 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002810 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002811 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002812 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002813 this->writeLayout(var->fModifiers.fLayout, id);
Ethan Nicholas45b0f152017-07-24 14:36:40 -04002814 if (var->fModifiers.fFlags & Modifiers::kFlat_Flag) {
2815 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2816 }
2817 if (var->fModifiers.fFlags & Modifiers::kNoPerspective_Flag) {
2818 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2819 fDecorationBuffer);
2820 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002821 }
2822}
2823
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002824void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002825 for (const auto& stmt : decl.fVars) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002826 SkASSERT(stmt->fKind == Statement::kVarDeclaration_Kind);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002827 VarDeclaration& varDecl = (VarDeclaration&) *stmt;
2828 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002829 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2830 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002831 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002832 Modifiers::kWriteOnly_Flag |
2833 Modifiers::kCoherent_Flag |
2834 Modifiers::kVolatile_Flag |
2835 Modifiers::kRestrict_Flag)));
ethannicholasb3058bd2016-07-01 08:22:01 -07002836 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002837 fVariableMap[var] = id;
2838 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002839 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002840 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002841 if (varDecl.fValue) {
2842 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002843 this->writeInstruction(SpvOpStore, id, value, out);
2844 }
2845 }
2846}
2847
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002848void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002849 switch (s.fKind) {
Ethan Nicholascb670962017-04-20 19:31:52 -04002850 case Statement::kNop_Kind:
2851 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002852 case Statement::kBlock_Kind:
2853 this->writeBlock((Block&) s, out);
2854 break;
2855 case Statement::kExpression_Kind:
2856 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2857 break;
Greg Daniel64773e62016-11-22 09:44:03 -05002858 case Statement::kReturn_Kind:
ethannicholasb3058bd2016-07-01 08:22:01 -07002859 this->writeReturnStatement((ReturnStatement&) s, out);
2860 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002861 case Statement::kVarDeclarations_Kind:
2862 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002863 break;
2864 case Statement::kIf_Kind:
2865 this->writeIfStatement((IfStatement&) s, out);
2866 break;
2867 case Statement::kFor_Kind:
2868 this->writeForStatement((ForStatement&) s, out);
2869 break;
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002870 case Statement::kWhile_Kind:
2871 this->writeWhileStatement((WhileStatement&) s, out);
2872 break;
2873 case Statement::kDo_Kind:
2874 this->writeDoStatement((DoStatement&) s, out);
2875 break;
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002876 case Statement::kSwitch_Kind:
2877 this->writeSwitchStatement((SwitchStatement&) s, out);
2878 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002879 case Statement::kBreak_Kind:
2880 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2881 break;
2882 case Statement::kContinue_Kind:
2883 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2884 break;
2885 case Statement::kDiscard_Kind:
2886 this->writeInstruction(SpvOpKill, out);
2887 break;
2888 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002889#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002890 ABORT("unsupported statement: %s", s.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002891#endif
2892 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002893 }
2894}
2895
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002896void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002897 for (size_t i = 0; i < b.fStatements.size(); i++) {
2898 this->writeStatement(*b.fStatements[i], out);
2899 }
2900}
2901
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002902void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002903 SpvId test = this->writeExpression(*stmt.fTest, out);
2904 SpvId ifTrue = this->nextId();
2905 SpvId ifFalse = this->nextId();
2906 if (stmt.fIfFalse) {
2907 SpvId end = this->nextId();
2908 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2909 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2910 this->writeLabel(ifTrue, out);
2911 this->writeStatement(*stmt.fIfTrue, out);
2912 if (fCurrentBlock) {
2913 this->writeInstruction(SpvOpBranch, end, out);
2914 }
2915 this->writeLabel(ifFalse, out);
2916 this->writeStatement(*stmt.fIfFalse, out);
2917 if (fCurrentBlock) {
2918 this->writeInstruction(SpvOpBranch, end, out);
2919 }
2920 this->writeLabel(end, out);
2921 } else {
2922 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2923 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2924 this->writeLabel(ifTrue, out);
2925 this->writeStatement(*stmt.fIfTrue, out);
2926 if (fCurrentBlock) {
2927 this->writeInstruction(SpvOpBranch, ifFalse, out);
2928 }
2929 this->writeLabel(ifFalse, out);
2930 }
2931}
2932
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002933void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002934 if (f.fInitializer) {
2935 this->writeStatement(*f.fInitializer, out);
2936 }
2937 SpvId header = this->nextId();
2938 SpvId start = this->nextId();
2939 SpvId body = this->nextId();
2940 SpvId next = this->nextId();
2941 fContinueTarget.push(next);
2942 SpvId end = this->nextId();
2943 fBreakTarget.push(end);
2944 this->writeInstruction(SpvOpBranch, header, out);
2945 this->writeLabel(header, out);
2946 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002947 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002948 this->writeLabel(start, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002949 if (f.fTest) {
2950 SpvId test = this->writeExpression(*f.fTest, out);
2951 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2952 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002953 this->writeLabel(body, out);
2954 this->writeStatement(*f.fStatement, out);
2955 if (fCurrentBlock) {
2956 this->writeInstruction(SpvOpBranch, next, out);
2957 }
2958 this->writeLabel(next, out);
2959 if (f.fNext) {
2960 this->writeExpression(*f.fNext, out);
2961 }
2962 this->writeInstruction(SpvOpBranch, header, out);
2963 this->writeLabel(end, out);
2964 fBreakTarget.pop();
2965 fContinueTarget.pop();
2966}
2967
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002968void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002969 SpvId header = this->nextId();
2970 SpvId start = this->nextId();
2971 SpvId body = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04002972 SpvId continueTarget = this->nextId();
2973 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002974 SpvId end = this->nextId();
2975 fBreakTarget.push(end);
2976 this->writeInstruction(SpvOpBranch, header, out);
2977 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04002978 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002979 this->writeInstruction(SpvOpBranch, start, out);
2980 this->writeLabel(start, out);
2981 SpvId test = this->writeExpression(*w.fTest, out);
2982 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2983 this->writeLabel(body, out);
2984 this->writeStatement(*w.fStatement, out);
2985 if (fCurrentBlock) {
Ethan Nicholas0d997662019-04-08 09:46:01 -04002986 this->writeInstruction(SpvOpBranch, continueTarget, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002987 }
Ethan Nicholas0d997662019-04-08 09:46:01 -04002988 this->writeLabel(continueTarget, out);
2989 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002990 this->writeLabel(end, out);
2991 fBreakTarget.pop();
2992 fContinueTarget.pop();
2993}
2994
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002995void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002996 // We believe the do loop code below will work, but Skia doesn't actually use them and
2997 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2998 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2999 // message, simply remove the error call below to see whether our do loop support actually
3000 // works.
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003001 fErrors.error(d.fOffset, "internal error: do loop support has been disabled in SPIR-V, see "
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003002 "SkSLSPIRVCodeGenerator.cpp for details");
3003
3004 SpvId header = this->nextId();
3005 SpvId start = this->nextId();
3006 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003007 SpvId continueTarget = this->nextId();
3008 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003009 SpvId end = this->nextId();
3010 fBreakTarget.push(end);
3011 this->writeInstruction(SpvOpBranch, header, out);
3012 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003013 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003014 this->writeInstruction(SpvOpBranch, start, out);
3015 this->writeLabel(start, out);
3016 this->writeStatement(*d.fStatement, out);
3017 if (fCurrentBlock) {
3018 this->writeInstruction(SpvOpBranch, next, out);
3019 }
3020 this->writeLabel(next, out);
3021 SpvId test = this->writeExpression(*d.fTest, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003022 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
3023 this->writeLabel(continueTarget, out);
3024 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003025 this->writeLabel(end, out);
3026 fBreakTarget.pop();
3027 fContinueTarget.pop();
3028}
3029
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003030void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
3031 SpvId value = this->writeExpression(*s.fValue, out);
3032 std::vector<SpvId> labels;
3033 SpvId end = this->nextId();
3034 SpvId defaultLabel = end;
3035 fBreakTarget.push(end);
3036 int size = 3;
3037 for (const auto& c : s.fCases) {
3038 SpvId label = this->nextId();
3039 labels.push_back(label);
3040 if (c->fValue) {
3041 size += 2;
3042 } else {
3043 defaultLabel = label;
3044 }
3045 }
3046 labels.push_back(end);
3047 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3048 this->writeOpCode(SpvOpSwitch, size, out);
3049 this->writeWord(value, out);
3050 this->writeWord(defaultLabel, out);
3051 for (size_t i = 0; i < s.fCases.size(); ++i) {
3052 if (!s.fCases[i]->fValue) {
3053 continue;
3054 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003055 SkASSERT(s.fCases[i]->fValue->fKind == Expression::kIntLiteral_Kind);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003056 this->writeWord(((IntLiteral&) *s.fCases[i]->fValue).fValue, out);
3057 this->writeWord(labels[i], out);
3058 }
3059 for (size_t i = 0; i < s.fCases.size(); ++i) {
3060 this->writeLabel(labels[i], out);
3061 for (const auto& stmt : s.fCases[i]->fStatements) {
3062 this->writeStatement(*stmt, out);
3063 }
3064 if (fCurrentBlock) {
3065 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3066 }
3067 }
3068 this->writeLabel(end, out);
3069 fBreakTarget.pop();
3070}
3071
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003072void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003073 if (r.fExpression) {
Greg Daniel64773e62016-11-22 09:44:03 -05003074 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003075 out);
3076 } else {
3077 this->writeInstruction(SpvOpReturn, out);
3078 }
3079}
3080
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003081void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003082 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003083 int invocations = 1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003084 for (const auto& e : fProgram) {
3085 if (e.fKind == ProgramElement::kModifiers_Kind) {
3086 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003087 if (m.fFlags & Modifiers::kIn_Flag) {
3088 if (m.fLayout.fInvocations != -1) {
3089 invocations = m.fLayout.fInvocations;
3090 }
3091 SpvId input;
3092 switch (m.fLayout.fPrimitive) {
3093 case Layout::kPoints_Primitive:
3094 input = SpvExecutionModeInputPoints;
3095 break;
3096 case Layout::kLines_Primitive:
3097 input = SpvExecutionModeInputLines;
3098 break;
3099 case Layout::kLinesAdjacency_Primitive:
3100 input = SpvExecutionModeInputLinesAdjacency;
3101 break;
3102 case Layout::kTriangles_Primitive:
3103 input = SpvExecutionModeTriangles;
3104 break;
3105 case Layout::kTrianglesAdjacency_Primitive:
3106 input = SpvExecutionModeInputTrianglesAdjacency;
3107 break;
3108 default:
3109 input = 0;
3110 break;
3111 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003112 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003113 if (input) {
3114 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3115 }
3116 } else if (m.fFlags & Modifiers::kOut_Flag) {
3117 SpvId output;
3118 switch (m.fLayout.fPrimitive) {
3119 case Layout::kPoints_Primitive:
3120 output = SpvExecutionModeOutputPoints;
3121 break;
3122 case Layout::kLineStrip_Primitive:
3123 output = SpvExecutionModeOutputLineStrip;
3124 break;
3125 case Layout::kTriangleStrip_Primitive:
3126 output = SpvExecutionModeOutputTriangleStrip;
3127 break;
3128 default:
3129 output = 0;
3130 break;
3131 }
3132 if (output) {
3133 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3134 }
3135 if (m.fLayout.fMaxVertices != -1) {
3136 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3137 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3138 out);
3139 }
3140 }
3141 }
3142 }
3143 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3144 invocations, out);
3145}
3146
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003147void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003148 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003149 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003150 std::set<SpvId> interfaceVars;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003151 // assign IDs to functions, determine sk_in size
3152 int skInSize = -1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003153 for (const auto& e : program) {
3154 switch (e.fKind) {
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003155 case ProgramElement::kFunction_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003156 FunctionDefinition& f = (FunctionDefinition&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003157 fFunctionMap[&f.fDeclaration] = this->nextId();
3158 break;
3159 }
3160 case ProgramElement::kModifiers_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003161 Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003162 if (m.fFlags & Modifiers::kIn_Flag) {
3163 switch (m.fLayout.fPrimitive) {
3164 case Layout::kPoints_Primitive: // break
3165 case Layout::kLines_Primitive:
3166 skInSize = 1;
3167 break;
3168 case Layout::kLinesAdjacency_Primitive: // break
3169 skInSize = 2;
3170 break;
3171 case Layout::kTriangles_Primitive: // break
3172 case Layout::kTrianglesAdjacency_Primitive:
3173 skInSize = 3;
3174 break;
3175 default:
3176 break;
3177 }
3178 }
3179 break;
3180 }
3181 default:
3182 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003183 }
3184 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003185 for (const auto& e : program) {
3186 if (e.fKind == ProgramElement::kInterfaceBlock_Kind) {
3187 InterfaceBlock& intf = (InterfaceBlock&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003188 if (SK_IN_BUILTIN == intf.fVariable.fModifiers.fLayout.fBuiltin) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003189 SkASSERT(skInSize != -1);
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003190 intf.fSizes.emplace_back(new IntLiteral(fContext, -1, skInSize));
3191 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003192 SpvId id = this->writeInterfaceBlock(intf);
Ethan Nicholas16c11962018-03-16 12:20:54 -04003193 if (((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
3194 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) &&
Chris Dalton2284aab2019-11-15 11:02:24 -07003195 intf.fVariable.fModifiers.fLayout.fBuiltin == -1 &&
3196 !is_dead(intf.fVariable)) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003197 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003198 }
3199 }
3200 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003201 for (const auto& e : program) {
3202 if (e.fKind == ProgramElement::kVar_Kind) {
3203 this->writeGlobalVars(program.fKind, ((VarDeclarations&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003204 }
3205 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003206 for (const auto& e : program) {
3207 if (e.fKind == ProgramElement::kFunction_Kind) {
3208 this->writeFunction(((FunctionDefinition&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003209 }
3210 }
ethannicholasd598f792016-07-25 10:08:54 -07003211 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003212 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07003213 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003214 main = entry.first;
3215 }
3216 }
Ethan Nicholas1a668d22019-04-18 10:37:40 -04003217 if (!main) {
3218 fErrors.error(0, "program does not contain a main() function");
3219 return;
3220 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003221 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003222 const Variable* var = entry.first;
Greg Daniel64773e62016-11-22 09:44:03 -05003223 if (var->fStorage == Variable::kGlobal_Storage &&
Ethan Nicholas16c11962018-03-16 12:20:54 -04003224 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
Chris Dalton2284aab2019-11-15 11:02:24 -07003225 (var->fModifiers.fFlags & Modifiers::kOut_Flag)) && !is_dead(*var)) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003226 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003227 }
3228 }
3229 this->writeCapabilities(out);
3230 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3231 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003232 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->fName.fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003233 (int32_t) interfaceVars.size(), out);
3234 switch (program.fKind) {
3235 case Program::kVertex_Kind:
3236 this->writeWord(SpvExecutionModelVertex, out);
3237 break;
3238 case Program::kFragment_Kind:
3239 this->writeWord(SpvExecutionModelFragment, out);
3240 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003241 case Program::kGeometry_Kind:
3242 this->writeWord(SpvExecutionModelGeometry, out);
3243 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003244 default:
3245 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003246 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003247 SpvId entryPoint = fFunctionMap[main];
3248 this->writeWord(entryPoint, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003249 this->writeString(main->fName.fChars, main->fName.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003250 for (int var : interfaceVars) {
3251 this->writeWord(var, out);
3252 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003253 if (program.fKind == Program::kGeometry_Kind) {
3254 this->writeGeometryShaderExecutionMode(entryPoint, out);
3255 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003256 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003257 this->writeInstruction(SpvOpExecutionMode,
3258 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003259 SpvExecutionModeOriginUpperLeft,
3260 out);
3261 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003262 for (const auto& e : program) {
3263 if (e.fKind == ProgramElement::kExtension_Kind) {
3264 this->writeInstruction(SpvOpSourceExtension, ((Extension&) e).fName.c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003265 }
3266 }
Greg Daniel64773e62016-11-22 09:44:03 -05003267
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003268 write_stringstream(fExtraGlobalsBuffer, out);
3269 write_stringstream(fNameBuffer, out);
3270 write_stringstream(fDecorationBuffer, out);
3271 write_stringstream(fConstantBuffer, out);
3272 write_stringstream(fExternalFunctionsBuffer, out);
3273 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003274}
3275
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003276bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003277 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003278 this->writeWord(SpvMagicNumber, *fOut);
3279 this->writeWord(SpvVersion, *fOut);
3280 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003281 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003282 this->writeInstructions(fProgram, buffer);
3283 this->writeWord(fIdCount, *fOut);
3284 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003285 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003286 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003287}
3288
3289}