blob: ce5d73be071feb863e3015b41d3c1d91d6eae0b3 [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 {
563 ABORT("invalid type: %s", type.description().c_str());
564 }
565 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800566 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700567 return result;
568 }
569 return entry->second;
570}
571
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400572SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400573 SkASSERT(type.kind() == Type::kSampler_Kind);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400574 this->getType(type);
575 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400576 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400577 return fImageTypeMap[key];
578}
579
ethannicholasd598f792016-07-25 10:08:54 -0700580SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400581 String key = function.fReturnType.description() + "(";
582 String separator;
ethannicholasd598f792016-07-25 10:08:54 -0700583 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700584 key += separator;
585 separator = ", ";
ethannicholasd598f792016-07-25 10:08:54 -0700586 key += function.fParameters[i]->fType.description();
ethannicholasb3058bd2016-07-01 08:22:01 -0700587 }
588 key += ")";
589 auto entry = fTypeMap.find(key);
590 if (entry == fTypeMap.end()) {
591 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -0700592 int32_t length = 3 + (int32_t) function.fParameters.size();
593 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700594 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -0700595 for (size_t i = 0; i < function.fParameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500596 // glslang seems to treat all function arguments as pointers whether they need to be or
597 // not. I was initially puzzled by this until I ran bizarre failures with certain
598 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700599 // failure case:
600 //
601 // void sphere(float x) {
602 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500603 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700604 // void map() {
605 // sphere(1.0);
606 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500607 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700608 // void main() {
609 // for (int i = 0; i < 1; i++) {
610 // map();
611 // }
612 // }
613 //
Greg Daniel64773e62016-11-22 09:44:03 -0500614 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
615 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700616 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
617 // the spec makes this make sense.
618// if (is_out(function->fParameters[i])) {
ethannicholasd598f792016-07-25 10:08:54 -0700619 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -0700620 SpvStorageClassFunction));
621// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700622// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700623// }
624 }
625 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
626 this->writeWord(result, fConstantBuffer);
627 this->writeWord(returnType, fConstantBuffer);
628 for (SpvId id : parameterTypes) {
629 this->writeWord(id, fConstantBuffer);
630 }
631 fTypeMap[key] = result;
632 return result;
633 }
634 return entry->second;
635}
636
ethannicholas8ac838d2016-11-22 08:39:36 -0800637SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
638 return this->getPointerType(type, fDefaultLayout, storageClass);
639}
640
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400641SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700642 SpvStorageClass_ storageClass) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400643 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400644 String key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700645 auto entry = fTypeMap.find(key);
646 if (entry == fTypeMap.end()) {
647 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500648 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700649 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700650 fTypeMap[key] = result;
651 return result;
652 }
653 return entry->second;
654}
655
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400656SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700657 switch (expr.fKind) {
658 case Expression::kBinary_Kind:
659 return this->writeBinaryExpression((BinaryExpression&) expr, out);
660 case Expression::kBoolLiteral_Kind:
661 return this->writeBoolLiteral((BoolLiteral&) expr);
662 case Expression::kConstructor_Kind:
663 return this->writeConstructor((Constructor&) expr, out);
664 case Expression::kIntLiteral_Kind:
665 return this->writeIntLiteral((IntLiteral&) expr);
666 case Expression::kFieldAccess_Kind:
667 return this->writeFieldAccess(((FieldAccess&) expr), out);
668 case Expression::kFloatLiteral_Kind:
669 return this->writeFloatLiteral(((FloatLiteral&) expr));
670 case Expression::kFunctionCall_Kind:
671 return this->writeFunctionCall((FunctionCall&) expr, out);
672 case Expression::kPrefix_Kind:
673 return this->writePrefixExpression((PrefixExpression&) expr, out);
674 case Expression::kPostfix_Kind:
675 return this->writePostfixExpression((PostfixExpression&) expr, out);
676 case Expression::kSwizzle_Kind:
677 return this->writeSwizzle((Swizzle&) expr, out);
678 case Expression::kVariableReference_Kind:
679 return this->writeVariableReference((VariableReference&) expr, out);
680 case Expression::kTernary_Kind:
681 return this->writeTernaryExpression((TernaryExpression&) expr, out);
682 case Expression::kIndex_Kind:
683 return this->writeIndexExpression((IndexExpression&) expr, out);
684 default:
685 ABORT("unsupported expression: %s", expr.description().c_str());
686 }
687 return -1;
688}
689
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400690SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700691 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400692 SkASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -0700693 int32_t intrinsicId;
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400694 if (c.fArguments.size() > 0) {
695 const Type& type = c.fArguments[0]->fType;
696 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
697 intrinsicId = std::get<1>(intrinsic->second);
698 } else if (is_signed(fContext, type)) {
699 intrinsicId = std::get<2>(intrinsic->second);
700 } else if (is_unsigned(fContext, type)) {
701 intrinsicId = std::get<3>(intrinsic->second);
702 } else if (is_bool(fContext, type)) {
703 intrinsicId = std::get<4>(intrinsic->second);
704 } else {
705 intrinsicId = std::get<1>(intrinsic->second);
706 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700707 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400708 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700709 }
710 switch (std::get<0>(intrinsic->second)) {
711 case kGLSL_STD_450_IntrinsicKind: {
712 SpvId result = this->nextId();
713 std::vector<SpvId> arguments;
714 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400715 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
716 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
717 } else {
718 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
719 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700720 }
721 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700722 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700723 this->writeWord(result, out);
724 this->writeWord(fGLSLExtendedInstructions, out);
725 this->writeWord(intrinsicId, out);
726 for (SpvId id : arguments) {
727 this->writeWord(id, out);
728 }
729 return result;
730 }
731 case kSPIRV_IntrinsicKind: {
732 SpvId result = this->nextId();
733 std::vector<SpvId> arguments;
734 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400735 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
736 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
737 } else {
738 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
739 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700740 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400741 if (c.fType != *fContext.fVoid_Type) {
742 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
743 this->writeWord(this->getType(c.fType), out);
744 this->writeWord(result, out);
745 } else {
746 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
747 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700748 for (SpvId id : arguments) {
749 this->writeWord(id, out);
750 }
751 return result;
752 }
753 case kSpecial_IntrinsicKind:
754 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
755 default:
756 ABORT("unsupported intrinsic kind");
757 }
758}
759
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500760std::vector<SpvId> SPIRVCodeGenerator::vectorize(
761 const std::vector<std::unique_ptr<Expression>>& args,
762 OutputStream& out) {
763 int vectorSize = 0;
764 for (const auto& a : args) {
765 if (a->fType.kind() == Type::kVector_Kind) {
766 if (vectorSize) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400767 SkASSERT(a->fType.columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500768 }
769 else {
770 vectorSize = a->fType.columns();
771 }
772 }
773 }
774 std::vector<SpvId> result;
775 for (const auto& a : args) {
776 SpvId raw = this->writeExpression(*a, out);
777 if (vectorSize && a->fType.kind() == Type::kScalar_Kind) {
778 SpvId vector = this->nextId();
779 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
780 this->writeWord(this->getType(a->fType.toCompound(fContext, vectorSize, 1)), out);
781 this->writeWord(vector, out);
782 for (int i = 0; i < vectorSize; i++) {
783 this->writeWord(raw, out);
784 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400785 this->writePrecisionModifier(a->fType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500786 result.push_back(vector);
787 } else {
788 result.push_back(raw);
789 }
790 }
791 return result;
792}
793
794void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
795 SpvId signedInst, SpvId unsignedInst,
796 const std::vector<SpvId>& args,
797 OutputStream& out) {
798 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
799 this->writeWord(this->getType(type), out);
800 this->writeWord(id, out);
801 this->writeWord(fGLSLExtendedInstructions, out);
802
803 if (is_float(fContext, type)) {
804 this->writeWord(floatInst, out);
805 } else if (is_signed(fContext, type)) {
806 this->writeWord(signedInst, out);
807 } else if (is_unsigned(fContext, type)) {
808 this->writeWord(unsignedInst, out);
809 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400810 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500811 }
812 for (SpvId a : args) {
813 this->writeWord(a, out);
814 }
815}
816
Greg Daniel64773e62016-11-22 09:44:03 -0500817SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400818 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700819 SpvId result = this->nextId();
820 switch (kind) {
821 case kAtan_SpecialIntrinsic: {
822 std::vector<SpvId> arguments;
823 for (size_t i = 0; i < c.fArguments.size(); i++) {
824 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
825 }
826 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700827 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700828 this->writeWord(result, out);
829 this->writeWord(fGLSLExtendedInstructions, out);
830 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
831 for (SpvId id : arguments) {
832 this->writeWord(id, out);
833 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400834 break;
835 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400836 case kSampledImage_SpecialIntrinsic: {
837 SkASSERT(2 == c.fArguments.size());
838 SpvId img = this->writeExpression(*c.fArguments[0], out);
839 SpvId sampler = this->writeExpression(*c.fArguments[1], out);
840 this->writeInstruction(SpvOpSampledImage,
841 this->getType(c.fType),
842 result,
843 img,
844 sampler,
845 out);
846 break;
847 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400848 case kSubpassLoad_SpecialIntrinsic: {
849 SpvId img = this->writeExpression(*c.fArguments[0], out);
850 std::vector<std::unique_ptr<Expression>> args;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700851 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
852 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
853 Constructor ctor(-1, *fContext.fFloat2_Type, std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400854 SpvId coords = this->writeConstantVector(ctor);
855 if (1 == c.fArguments.size()) {
856 this->writeInstruction(SpvOpImageRead,
857 this->getType(c.fType),
858 result,
859 img,
860 coords,
861 out);
862 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400863 SkASSERT(2 == c.fArguments.size());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400864 SpvId sample = this->writeExpression(*c.fArguments[1], out);
865 this->writeInstruction(SpvOpImageRead,
866 this->getType(c.fType),
867 result,
868 img,
869 coords,
870 SpvImageOperandsSampleMask,
871 sample,
872 out);
873 }
874 break;
875 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700876 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500877 SpvOp_ op = SpvOpImageSampleImplicitLod;
878 switch (c.fArguments[0]->fType.dimensions()) {
879 case SpvDim1D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400880 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500881 op = SpvOpImageSampleProjImplicitLod;
882 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400883 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500884 }
885 break;
886 case SpvDim2D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400887 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500888 op = SpvOpImageSampleProjImplicitLod;
889 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400890 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500891 }
892 break;
893 case SpvDim3D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400894 if (c.fArguments[1]->fType == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500895 op = SpvOpImageSampleProjImplicitLod;
896 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400897 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500898 }
899 break;
900 case SpvDimCube: // fall through
901 case SpvDimRect: // fall through
902 case SpvDimBuffer: // fall through
903 case SpvDimSubpassData:
904 break;
905 }
ethannicholasd598f792016-07-25 10:08:54 -0700906 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700907 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
908 SpvId uv = this->writeExpression(*c.fArguments[1], out);
909 if (c.fArguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500910 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700911 SpvImageOperandsBiasMask,
912 this->writeExpression(*c.fArguments[2], out),
913 out);
914 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400915 SkASSERT(c.fArguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500916 if (fProgram.fSettings.fSharpenTextures) {
917 FloatLiteral lodBias(fContext, -1, -0.5);
918 this->writeInstruction(op, type, result, sampler, uv,
919 SpvImageOperandsBiasMask,
920 this->writeFloatLiteral(lodBias),
921 out);
922 } else {
923 this->writeInstruction(op, type, result, sampler, uv,
924 out);
925 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700926 }
927 break;
928 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500929 case kMod_SpecialIntrinsic: {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500930 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400931 SkASSERT(args.size() == 2);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500932 const Type& operandType = c.fArguments[0]->fType;
933 SpvOp_ op;
934 if (is_float(fContext, operandType)) {
935 op = SpvOpFMod;
936 } else if (is_signed(fContext, operandType)) {
937 op = SpvOpSMod;
938 } else if (is_unsigned(fContext, operandType)) {
939 op = SpvOpUMod;
940 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400941 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500942 return 0;
943 }
944 this->writeOpCode(op, 5, out);
945 this->writeWord(this->getType(operandType), out);
946 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500947 this->writeWord(args[0], out);
948 this->writeWord(args[1], out);
949 break;
950 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700951 case kDFdy_SpecialIntrinsic: {
952 SpvId fn = this->writeExpression(*c.fArguments[0], out);
953 this->writeOpCode(SpvOpDPdy, 4, out);
954 this->writeWord(this->getType(c.fType), out);
955 this->writeWord(result, out);
956 this->writeWord(fn, out);
957 if (fProgram.fSettings.fFlipY) {
958 // Flipping Y also negates the Y derivatives.
959 SpvId flipped = this->nextId();
960 this->writeInstruction(SpvOpFNegate, this->getType(c.fType), flipped, result, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -0400961 this->writePrecisionModifier(c.fType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700962 return flipped;
963 }
964 break;
965 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500966 case kClamp_SpecialIntrinsic: {
967 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400968 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500969 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
970 GLSLstd450UClamp, args, out);
971 break;
972 }
973 case kMax_SpecialIntrinsic: {
974 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400975 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500976 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMax, GLSLstd450SMax,
977 GLSLstd450UMax, args, out);
978 break;
979 }
980 case kMin_SpecialIntrinsic: {
981 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400982 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500983 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMin, GLSLstd450SMin,
984 GLSLstd450UMin, args, out);
985 break;
986 }
987 case kMix_SpecialIntrinsic: {
988 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400989 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500990 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMix, SpvOpUndef,
991 SpvOpUndef, args, out);
992 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500993 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400994 case kSaturate_SpecialIntrinsic: {
995 SkASSERT(c.fArguments.size() == 1);
996 std::vector<std::unique_ptr<Expression>> finalArgs;
997 finalArgs.push_back(c.fArguments[0]->clone());
998 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 0));
999 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 1));
1000 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
1001 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
1002 GLSLstd450UClamp, spvArgs, out);
1003 break;
1004 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001005 }
1006 return result;
1007}
1008
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001009SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001010 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07001011 if (entry == fFunctionMap.end()) {
1012 return this->writeIntrinsicCall(c, out);
1013 }
1014 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001015 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
ethannicholasb3058bd2016-07-01 08:22:01 -07001016 std::vector<SpvId> arguments;
1017 for (size_t i = 0; i < c.fArguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001018 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001019 // passed directly
1020 SpvId tmpVar;
1021 // if we need a temporary var to store this argument, this is the value to store in the var
1022 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -07001023 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001024 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
1025 SpvId ptr = lv->getPointer();
1026 if (ptr) {
1027 arguments.push_back(ptr);
1028 continue;
1029 } else {
1030 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1031 // copy it into a temp, call the function, read the value out of the temp, and then
1032 // update the lvalue.
1033 tmpValueId = lv->load(out);
1034 tmpVar = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001035 lvalues.push_back(std::make_tuple(tmpVar, &c.fArguments[i]->fType, std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001036 }
1037 } else {
1038 // see getFunctionType for an explanation of why we're always using pointer parameters
1039 tmpValueId = this->writeExpression(*c.fArguments[i], out);
1040 tmpVar = this->nextId();
1041 }
Greg Daniel64773e62016-11-22 09:44:03 -05001042 this->writeInstruction(SpvOpVariable,
1043 this->getPointerType(c.fArguments[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -07001044 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001045 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001046 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001047 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001048 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1049 arguments.push_back(tmpVar);
1050 }
1051 SpvId result = this->nextId();
1052 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001053 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001054 this->writeWord(result, out);
1055 this->writeWord(entry->second, out);
1056 for (SpvId id : arguments) {
1057 this->writeWord(id, out);
1058 }
1059 // now that the call is complete, we may need to update some lvalues with the new values of out
1060 // arguments
1061 for (const auto& tuple : lvalues) {
1062 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001063 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1064 out);
1065 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001066 std::get<2>(tuple)->store(load, out);
1067 }
1068 return result;
1069}
1070
ethannicholasf789b382016-08-03 12:43:36 -07001071SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001072 SkASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001073 SpvId result = this->nextId();
1074 std::vector<SpvId> arguments;
1075 for (size_t i = 0; i < c.fArguments.size(); i++) {
1076 arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1077 }
ethannicholasd598f792016-07-25 10:08:54 -07001078 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001079 if (c.fArguments.size() == 1) {
1080 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001081 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001082 this->writeWord(type, fConstantBuffer);
1083 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001084 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001085 this->writeWord(arguments[0], fConstantBuffer);
1086 }
1087 } else {
Greg Daniel64773e62016-11-22 09:44:03 -05001088 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001089 fConstantBuffer);
1090 this->writeWord(type, fConstantBuffer);
1091 this->writeWord(result, fConstantBuffer);
1092 for (SpvId id : arguments) {
1093 this->writeWord(id, fConstantBuffer);
1094 }
1095 }
1096 return result;
1097}
1098
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001099SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001100 SkASSERT(c.fType.isFloat());
1101 SkASSERT(c.fArguments.size() == 1);
1102 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001103 SpvId result = this->nextId();
1104 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001105 if (c.fArguments[0]->fType.isSigned()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001106 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001107 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001108 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001109 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Greg Daniel64773e62016-11-22 09:44:03 -05001110 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001111 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001112 }
1113 return result;
1114}
1115
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001116SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001117 SkASSERT(c.fType.isSigned());
1118 SkASSERT(c.fArguments.size() == 1);
1119 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001120 SpvId result = this->nextId();
1121 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001122 if (c.fArguments[0]->fType.isFloat()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001123 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001124 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001125 }
1126 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001127 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001128 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001129 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001130 }
1131 return result;
1132}
1133
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001134SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001135 SkASSERT(c.fType.isUnsigned());
1136 SkASSERT(c.fArguments.size() == 1);
1137 SkASSERT(c.fArguments[0]->fType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001138 SpvId result = this->nextId();
1139 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001140 if (c.fArguments[0]->fType.isFloat()) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001141 this->writeInstruction(SpvOpConvertFToU, this->getType(c.fType), result, parameter,
1142 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001143 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001144 SkASSERT(c.fArguments[0]->fType.isSigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001145 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
1146 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001147 }
1148 return result;
1149}
1150
Ethan Nicholas84645e32017-02-09 13:57:14 -05001151void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001152 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001153 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001154 SpvId zeroId = this->writeFloatLiteral(zero);
1155 std::vector<SpvId> columnIds;
1156 for (int column = 0; column < type.columns(); column++) {
1157 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1158 out);
1159 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1160 out);
1161 SpvId columnId = this->nextId();
1162 this->writeWord(columnId, out);
1163 columnIds.push_back(columnId);
1164 for (int row = 0; row < type.columns(); row++) {
1165 this->writeWord(row == column ? diagonal : zeroId, out);
1166 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001167 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001168 }
1169 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1170 out);
1171 this->writeWord(this->getType(type), out);
1172 this->writeWord(id, out);
1173 for (SpvId id : columnIds) {
1174 this->writeWord(id, out);
1175 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001176 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001177}
1178
1179void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001180 const Type& dstType, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001181 SkASSERT(srcType.kind() == Type::kMatrix_Kind);
1182 SkASSERT(dstType.kind() == Type::kMatrix_Kind);
1183 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001184 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1185 srcType.rows(),
1186 1));
1187 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1188 dstType.rows(),
1189 1));
1190 SpvId zeroId;
1191 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001192 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001193 zeroId = this->writeFloatLiteral(zero);
1194 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001195 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001196 zeroId = this->writeIntLiteral(zero);
1197 } else {
1198 ABORT("unsupported matrix component type");
1199 }
1200 SpvId zeroColumn = 0;
1201 SpvId columns[4];
1202 for (int i = 0; i < dstType.columns(); i++) {
1203 if (i < srcType.columns()) {
1204 // we're still inside the src matrix, copy the column
1205 SpvId srcColumn = this->nextId();
1206 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001207 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001208 SpvId dstColumn;
1209 if (srcType.rows() == dstType.rows()) {
1210 // columns are equal size, don't need to do anything
1211 dstColumn = srcColumn;
1212 }
1213 else if (dstType.rows() > srcType.rows()) {
1214 // dst column is bigger, need to zero-pad it
1215 dstColumn = this->nextId();
1216 int delta = dstType.rows() - srcType.rows();
1217 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1218 this->writeWord(dstColumnType, out);
1219 this->writeWord(dstColumn, out);
1220 this->writeWord(srcColumn, out);
1221 for (int i = 0; i < delta; ++i) {
1222 this->writeWord(zeroId, out);
1223 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001224 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001225 }
1226 else {
1227 // dst column is smaller, need to swizzle the src column
1228 dstColumn = this->nextId();
1229 int count = dstType.rows();
1230 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1231 this->writeWord(dstColumnType, out);
1232 this->writeWord(dstColumn, out);
1233 this->writeWord(srcColumn, out);
1234 this->writeWord(srcColumn, out);
1235 for (int i = 0; i < count; i++) {
1236 this->writeWord(i, out);
1237 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001238 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001239 }
1240 columns[i] = dstColumn;
1241 } else {
1242 // we're past the end of the src matrix, need a vector of zeroes
1243 if (!zeroColumn) {
1244 zeroColumn = this->nextId();
1245 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1246 this->writeWord(dstColumnType, out);
1247 this->writeWord(zeroColumn, out);
1248 for (int i = 0; i < dstType.rows(); ++i) {
1249 this->writeWord(zeroId, out);
1250 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001251 this->writePrecisionModifier(dstType, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001252 }
1253 columns[i] = zeroColumn;
1254 }
1255 }
1256 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1257 this->writeWord(this->getType(dstType), out);
1258 this->writeWord(id, out);
1259 for (int i = 0; i < dstType.columns(); i++) {
1260 this->writeWord(columns[i], out);
1261 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001262 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001263}
1264
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001265void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1266 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001267 std::vector<SpvId>* columnIds,
1268 int* currentCount, int rows, SpvId entry,
1269 OutputStream& out) {
1270 SkASSERT(*currentCount < rows);
1271 ++(*currentCount);
1272 currentColumn->push_back(entry);
1273 if (*currentCount == rows) {
1274 *currentCount = 0;
1275 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1276 this->writeWord(columnType, out);
1277 SpvId columnId = this->nextId();
1278 this->writeWord(columnId, out);
1279 columnIds->push_back(columnId);
1280 for (SpvId id : *currentColumn) {
1281 this->writeWord(id, out);
1282 }
1283 currentColumn->clear();
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001284 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001285 }
1286}
1287
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001288SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001289 SkASSERT(c.fType.kind() == Type::kMatrix_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001290 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1291 // an instruction
1292 std::vector<SpvId> arguments;
1293 for (size_t i = 0; i < c.fArguments.size(); i++) {
1294 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1295 }
1296 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001297 int rows = c.fType.rows();
1298 int columns = c.fType.columns();
Ethan Nicholas84645e32017-02-09 13:57:14 -05001299 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1300 this->writeUniformScaleMatrix(result, arguments[0], c.fType, out);
1301 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kMatrix_Kind) {
1302 this->writeMatrixCopy(result, arguments[0], c.fArguments[0]->fType, c.fType, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001303 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kVector_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001304 SkASSERT(c.fType.rows() == 2 && c.fType.columns() == 2);
1305 SkASSERT(c.fArguments[0]->fType.columns() == 4);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001306 SpvId componentType = this->getType(c.fType.componentType());
1307 SpvId v[4];
1308 for (int i = 0; i < 4; ++i) {
1309 v[i] = this->nextId();
1310 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i, out);
1311 }
1312 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, 2, 1));
1313 SpvId column1 = this->nextId();
1314 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1315 SpvId column2 = this->nextId();
1316 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
1317 this->writeInstruction(SpvOpCompositeConstruct, this->getType(c.fType), result, column1,
1318 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001319 } else {
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001320 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001321 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001322 // ids of vectors and scalars we have written to the current column so far
1323 std::vector<SpvId> currentColumn;
1324 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001325 int currentCount = 0;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001326 Precision precision = c.fType.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001327 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001328 if (currentCount == 0 && c.fArguments[i]->fType.kind() == Type::kVector_Kind &&
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001329 c.fArguments[i]->fType.columns() == c.fType.rows()) {
1330 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001331 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001332 } else {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001333 if (c.fArguments[i]->fType.columns() == 1) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001334 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1335 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001336 } else {
1337 SpvId componentType = this->getType(c.fArguments[i]->fType.componentType());
Ethan Nicholas811b9442018-05-11 13:16:03 -04001338 for (int j = 0; j < c.fArguments[i]->fType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001339 SpvId swizzle = this->nextId();
1340 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1341 arguments[i], j, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001342 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1343 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001344 }
1345 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001346 }
1347 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001348 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001349 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001350 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001351 this->writeWord(result, out);
1352 for (SpvId id : columnIds) {
1353 this->writeWord(id, out);
1354 }
1355 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001356 this->writePrecisionModifier(c.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001357 return result;
1358}
1359
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001360SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001361 SkASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001362 if (c.isConstant()) {
1363 return this->writeConstantVector(c);
1364 }
1365 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1366 // an instruction
1367 std::vector<SpvId> arguments;
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001368 for (size_t i = 0; i < c.fArguments.size(); i++) {
1369 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
1370 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1371 // extract the components and convert them in that case manually. On top of that,
1372 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1373 // doesn't handle vector arguments at all, so we always extract vector components and
1374 // pass them into OpCreateComposite individually.
1375 SpvId vec = this->writeExpression(*c.fArguments[i], out);
1376 SpvOp_ op = SpvOpUndef;
1377 const Type& src = c.fArguments[i]->fType.componentType();
1378 const Type& dst = c.fType.componentType();
1379 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1380 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1381 if (c.fArguments.size() == 1) {
1382 return vec;
1383 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001384 } else if (src == *fContext.fInt_Type ||
1385 src == *fContext.fShort_Type ||
1386 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001387 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001388 } else if (src == *fContext.fUInt_Type ||
1389 src == *fContext.fUShort_Type ||
1390 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001391 op = SpvOpConvertUToF;
1392 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001393 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001394 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001395 } else if (dst == *fContext.fInt_Type ||
1396 dst == *fContext.fShort_Type ||
1397 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001398 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1399 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001400 } else if (src == *fContext.fInt_Type ||
1401 src == *fContext.fShort_Type ||
1402 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001403 if (c.fArguments.size() == 1) {
1404 return vec;
1405 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001406 } else if (src == *fContext.fUInt_Type ||
1407 src == *fContext.fUShort_Type ||
1408 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001409 op = SpvOpBitcast;
1410 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001411 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001412 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001413 } else if (dst == *fContext.fUInt_Type ||
1414 dst == *fContext.fUShort_Type ||
1415 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001416 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1417 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001418 } else if (src == *fContext.fInt_Type ||
1419 src == *fContext.fShort_Type ||
1420 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001421 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001422 } else if (src == *fContext.fUInt_Type ||
1423 src == *fContext.fUShort_Type ||
1424 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001425 if (c.fArguments.size() == 1) {
1426 return vec;
1427 }
1428 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001429 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001430 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001431 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001432 for (int j = 0; j < c.fArguments[i]->fType.columns(); j++) {
1433 SpvId swizzle = this->nextId();
1434 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1435 out);
1436 if (op != SpvOpUndef) {
1437 SpvId cast = this->nextId();
1438 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1439 arguments.push_back(cast);
1440 } else {
1441 arguments.push_back(swizzle);
1442 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001443 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001444 } else {
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001445 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1446 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001447 }
1448 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001449 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1450 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1451 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001452 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001453 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001454 this->writeWord(arguments[0], out);
1455 }
1456 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001457 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001458 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001459 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001460 this->writeWord(result, out);
1461 for (SpvId id : arguments) {
1462 this->writeWord(id, out);
1463 }
1464 }
1465 return result;
1466}
1467
Ethan Nicholasbd553222017-07-18 15:54:59 -04001468SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001469 SkASSERT(c.fType.kind() == Type::kArray_Kind);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001470 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1471 // an instruction
1472 std::vector<SpvId> arguments;
1473 for (size_t i = 0; i < c.fArguments.size(); i++) {
1474 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1475 }
1476 SpvId result = this->nextId();
1477 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
1478 this->writeWord(this->getType(c.fType), out);
1479 this->writeWord(result, out);
1480 for (SpvId id : arguments) {
1481 this->writeWord(id, out);
1482 }
1483 return result;
1484}
1485
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001486SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001487 if (c.fArguments.size() == 1 &&
1488 this->getActualType(c.fType) == this->getActualType(c.fArguments[0]->fType)) {
1489 return this->writeExpression(*c.fArguments[0], out);
1490 }
1491 if (c.fType == *fContext.fFloat_Type || c.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001492 return this->writeFloatConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001493 } else if (c.fType == *fContext.fInt_Type ||
1494 c.fType == *fContext.fShort_Type ||
1495 c.fType == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001496 return this->writeIntConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001497 } else if (c.fType == *fContext.fUInt_Type ||
1498 c.fType == *fContext.fUShort_Type ||
1499 c.fType == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001500 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001501 }
ethannicholasd598f792016-07-25 10:08:54 -07001502 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001503 case Type::kVector_Kind:
1504 return this->writeVectorConstructor(c, out);
1505 case Type::kMatrix_Kind:
1506 return this->writeMatrixConstructor(c, out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001507 case Type::kArray_Kind:
1508 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001509 default:
1510 ABORT("unsupported constructor: %s", c.description().c_str());
1511 }
1512}
1513
1514SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1515 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001516 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001517 return SpvStorageClassInput;
1518 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001519 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001520 return SpvStorageClassOutput;
1521 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001522 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001523 return SpvStorageClassPushConstant;
1524 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001525 return SpvStorageClassUniform;
1526 } else {
1527 return SpvStorageClassFunction;
1528 }
1529}
1530
ethannicholasf789b382016-08-03 12:43:36 -07001531SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001532 switch (expr.fKind) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001533 case Expression::kVariableReference_Kind: {
1534 const Variable& var = ((VariableReference&) expr).fVariable;
1535 if (var.fStorage != Variable::kGlobal_Storage) {
1536 return SpvStorageClassFunction;
1537 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001538 SpvStorageClass_ result = get_storage_class(var.fModifiers);
1539 if (result == SpvStorageClassFunction) {
1540 result = SpvStorageClassPrivate;
1541 }
1542 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001543 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001544 case Expression::kFieldAccess_Kind:
1545 return get_storage_class(*((FieldAccess&) expr).fBase);
1546 case Expression::kIndex_Kind:
1547 return get_storage_class(*((IndexExpression&) expr).fBase);
1548 default:
1549 return SpvStorageClassFunction;
1550 }
1551}
1552
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001553std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001554 std::vector<SpvId> chain;
1555 switch (expr.fKind) {
1556 case Expression::kIndex_Kind: {
1557 IndexExpression& indexExpr = (IndexExpression&) expr;
1558 chain = this->getAccessChain(*indexExpr.fBase, out);
1559 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1560 break;
1561 }
1562 case Expression::kFieldAccess_Kind: {
1563 FieldAccess& fieldExpr = (FieldAccess&) expr;
1564 chain = this->getAccessChain(*fieldExpr.fBase, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001565 IntLiteral index(fContext, -1, fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001566 chain.push_back(this->writeIntLiteral(index));
1567 break;
1568 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001569 default: {
1570 SpvId id = this->getLValue(expr, out)->getPointer();
1571 SkASSERT(id != 0);
1572 chain.push_back(id);
1573 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001574 }
1575 return chain;
1576}
1577
1578class PointerLValue : public SPIRVCodeGenerator::LValue {
1579public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001580 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1581 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001582 : fGen(gen)
1583 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001584 , fType(type)
1585 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001586
1587 virtual SpvId getPointer() override {
1588 return fPointer;
1589 }
1590
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001591 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001592 SpvId result = fGen.nextId();
1593 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001594 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001595 return result;
1596 }
1597
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001598 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001599 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1600 }
1601
1602private:
1603 SPIRVCodeGenerator& fGen;
1604 const SpvId fPointer;
1605 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001606 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001607};
1608
1609class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1610public:
Greg Daniel64773e62016-11-22 09:44:03 -05001611 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001612 const Type& baseType, const Type& swizzleType,
1613 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001614 : fGen(gen)
1615 , fVecPointer(vecPointer)
1616 , fComponents(components)
1617 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001618 , fSwizzleType(swizzleType)
1619 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001620
1621 virtual SpvId getPointer() override {
1622 return 0;
1623 }
1624
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001625 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001626 SpvId base = fGen.nextId();
1627 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001628 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001629 SpvId result = fGen.nextId();
1630 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1631 fGen.writeWord(fGen.getType(fSwizzleType), out);
1632 fGen.writeWord(result, out);
1633 fGen.writeWord(base, out);
1634 fGen.writeWord(base, out);
1635 for (int component : fComponents) {
1636 fGen.writeWord(component, out);
1637 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001638 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001639 return result;
1640 }
1641
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001642 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001643 // use OpVectorShuffle to mix and match the vector components. We effectively create
1644 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001645 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001646 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001647 // float3L = ...;
1648 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001649 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001650 // 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 -07001651 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1652 // (3, 1, 4).
1653 SpvId base = fGen.nextId();
1654 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1655 SpvId shuffle = fGen.nextId();
1656 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1657 fGen.writeWord(fGen.getType(fBaseType), out);
1658 fGen.writeWord(shuffle, out);
1659 fGen.writeWord(base, out);
1660 fGen.writeWord(value, out);
1661 for (int i = 0; i < fBaseType.columns(); i++) {
1662 // current offset into the virtual vector, defaults to pulling the unmodified
1663 // value from the left side
1664 int offset = i;
1665 // check to see if we are writing this component
1666 for (size_t j = 0; j < fComponents.size(); j++) {
1667 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001668 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001669 // the correct component of the right side instead of preserving the
1670 // value from the left
1671 offset = (int) (j + fBaseType.columns());
1672 break;
1673 }
1674 }
1675 fGen.writeWord(offset, out);
1676 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001677 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001678 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1679 }
1680
1681private:
1682 SPIRVCodeGenerator& fGen;
1683 const SpvId fVecPointer;
1684 const std::vector<int>& fComponents;
1685 const Type& fBaseType;
1686 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001687 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001688};
1689
Greg Daniel64773e62016-11-22 09:44:03 -05001690std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001691 OutputStream& out) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001692 Precision precision = expr.fType.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001693 switch (expr.fKind) {
1694 case Expression::kVariableReference_Kind: {
Ethan Nicholas5226b772018-05-03 16:20:41 -04001695 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07001696 const Variable& var = ((VariableReference&) expr).fVariable;
Ethan Nicholas5226b772018-05-03 16:20:41 -04001697 if (var.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
1698 type = this->getType(Type("sk_in", Type::kArray_Kind, var.fType.componentType(),
1699 fSkInCount));
1700 } else {
1701 type = this->getType(expr.fType);
1702 }
ethannicholasd598f792016-07-25 10:08:54 -07001703 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001704 SkASSERT(entry != fVariableMap.end());
Ethan Nicholas5226b772018-05-03 16:20:41 -04001705 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(*this,
1706 entry->second,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001707 type,
1708 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001709 }
1710 case Expression::kIndex_Kind: // fall through
1711 case Expression::kFieldAccess_Kind: {
1712 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1713 SpvId member = this->nextId();
1714 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001715 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001716 this->writeWord(member, out);
1717 for (SpvId idx : chain) {
1718 this->writeWord(idx, out);
1719 }
1720 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -04001721 *this,
1722 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001723 this->getType(expr.fType),
1724 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001725 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001726 case Expression::kSwizzle_Kind: {
1727 Swizzle& swizzle = (Swizzle&) expr;
1728 size_t count = swizzle.fComponents.size();
1729 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001730 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001731 if (count == 1) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001732 IntLiteral index(fContext, -1, swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001733 SpvId member = this->nextId();
1734 this->writeInstruction(SpvOpAccessChain,
Greg Daniel64773e62016-11-22 09:44:03 -05001735 this->getPointerType(swizzle.fType,
1736 get_storage_class(*swizzle.fBase)),
1737 member,
1738 base,
1739 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001740 out);
1741 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1742 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001743 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001744 this->getType(expr.fType),
1745 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001746 } else {
1747 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
Greg Daniel64773e62016-11-22 09:44:03 -05001748 *this,
1749 base,
1750 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001751 swizzle.fBase->fType,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001752 expr.fType,
1753 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001754 }
1755 }
Ethan Nicholasa583b812018-01-18 13:32:11 -05001756 case Expression::kTernary_Kind: {
1757 TernaryExpression& t = (TernaryExpression&) expr;
1758 SpvId test = this->writeExpression(*t.fTest, out);
1759 SpvId end = this->nextId();
1760 SpvId ifTrueLabel = this->nextId();
1761 SpvId ifFalseLabel = this->nextId();
1762 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1763 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1764 this->writeLabel(ifTrueLabel, out);
1765 SpvId ifTrue = this->getLValue(*t.fIfTrue, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001766 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001767 this->writeInstruction(SpvOpBranch, end, out);
1768 ifTrueLabel = fCurrentBlock;
1769 SpvId ifFalse = this->getLValue(*t.fIfFalse, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001770 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001771 ifFalseLabel = fCurrentBlock;
1772 this->writeInstruction(SpvOpBranch, end, out);
1773 SpvId result = this->nextId();
1774 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1775 ifTrueLabel, ifFalse, ifFalseLabel, out);
1776 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1777 *this,
1778 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001779 this->getType(expr.fType),
1780 precision));
Ethan Nicholasa583b812018-01-18 13:32:11 -05001781 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001782 default:
1783 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001784 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001785 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1786 // caught by IRGenerator
1787 SpvId result = this->nextId();
1788 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001789 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1790 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001791 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1792 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1793 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001794 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001795 this->getType(expr.fType),
1796 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001797 }
1798}
1799
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001800SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001801 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001802 auto entry = fVariableMap.find(&ref.fVariable);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001803 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001804 SpvId var = entry->second;
ethannicholasd598f792016-07-25 10:08:54 -07001805 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001806 this->writePrecisionModifier(ref.fVariable.fType, result);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001807 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
1808 fProgram.fSettings.fFlipY) {
1809 // need to remap to a top-left coordinate system
Greg Daniele6ab9982018-08-22 13:56:32 +00001810 if (fRTHeightStructId == (SpvId) -1) {
1811 // height variable hasn't been written yet
1812 std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors));
1813 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
1814 std::vector<Type::Field> fields;
Ethan Nicholas0be34802019-08-15 12:36:58 -04001815 SkASSERT(fProgram.fSettings.fRTHeightOffset >= 0);
1816 fields.emplace_back(Modifiers(Layout(0, -1, fProgram.fSettings.fRTHeightOffset, -1,
1817 -1, -1, -1, -1, Layout::Format::kUnspecified,
1818 Layout::kUnspecified_Primitive, -1, -1, "",
1819 Layout::kNo_Key, Layout::CType::kDefault), 0),
1820 SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
Greg Daniele6ab9982018-08-22 13:56:32 +00001821 StringFragment name("sksl_synthetic_uniforms");
1822 Type intfStruct(-1, name, fields);
Ethan Nicholas0be34802019-08-15 12:36:58 -04001823 int binding;
1824 int set;
1825#ifdef SK_VULKAN
1826 const GrVkCaps* vkCaps = fProgram.fSettings.fVkCaps;
1827 SkASSERT(vkCaps);
1828 binding = vkCaps->getFragmentUniformBinding();
1829 set = vkCaps->getFragmentUniformSet();
1830#else
1831 binding = 0;
1832 set = 0;
1833#endif
1834 Layout layout(0, -1, -1, binding, -1, set, -1, -1, Layout::Format::kUnspecified,
Greg Daniele6ab9982018-08-22 13:56:32 +00001835 Layout::kUnspecified_Primitive, -1, -1, "", Layout::kNo_Key,
Ethan Nicholas78aceb22018-08-31 16:13:58 -04001836 Layout::CType::kDefault);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001837 Variable* intfVar = (Variable*) fSynthetics.takeOwnership(std::unique_ptr<Symbol>(
1838 new Variable(-1,
1839 Modifiers(layout, Modifiers::kUniform_Flag),
1840 name,
1841 intfStruct,
1842 Variable::kGlobal_Storage)));
Greg Daniele6ab9982018-08-22 13:56:32 +00001843 InterfaceBlock intf(-1, intfVar, name, String(""),
1844 std::vector<std::unique_ptr<Expression>>(), st);
1845 fRTHeightStructId = this->writeInterfaceBlock(intf);
1846 fRTHeightFieldIndex = 0;
1847 }
1848 SkASSERT(fRTHeightFieldIndex != (SpvId) -1);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001849 // write float4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, gl_FragCoord.w)
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001850 SpvId xId = this->nextId();
1851 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1852 result, 0, out);
Greg Daniele6ab9982018-08-22 13:56:32 +00001853 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1854 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1855 SpvId heightPtr = this->nextId();
1856 this->writeOpCode(SpvOpAccessChain, 5, out);
1857 this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out);
1858 this->writeWord(heightPtr, out);
1859 this->writeWord(fRTHeightStructId, out);
1860 this->writeWord(fieldIndexId, out);
1861 SpvId heightRead = this->nextId();
1862 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1863 heightPtr, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001864 SpvId rawYId = this->nextId();
1865 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1866 result, 1, out);
1867 SpvId flippedYId = this->nextId();
1868 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
Greg Daniele6ab9982018-08-22 13:56:32 +00001869 heightRead, rawYId, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001870 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001871 SpvId zeroId = writeFloatLiteral(zero);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001872 FloatLiteral one(fContext, -1, 1.0);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001873 SpvId wId = this->nextId();
1874 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), wId,
1875 result, 3, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001876 SpvId flipped = this->nextId();
1877 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001878 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001879 this->writeWord(flipped, out);
1880 this->writeWord(xId, out);
1881 this->writeWord(flippedYId, out);
1882 this->writeWord(zeroId, out);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001883 this->writeWord(wId, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001884 return flipped;
1885 }
Chris Daltonb91c4662018-08-01 10:46:22 -06001886 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
1887 !fProgram.fSettings.fFlipY) {
1888 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1889 // the default convention of "counter-clockwise face is front".
1890 SpvId inverse = this->nextId();
1891 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1892 result, out);
1893 return inverse;
1894 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001895 return result;
1896}
1897
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001898SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001899 if (expr.fBase->fType.kind() == Type::Kind::kVector_Kind) {
1900 SpvId base = this->writeExpression(*expr.fBase, out);
1901 SpvId index = this->writeExpression(*expr.fIndex, out);
1902 SpvId result = this->nextId();
1903 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.fType), result, base,
1904 index, out);
1905 return result;
1906 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001907 return getLValue(expr, out)->load(out);
1908}
1909
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001910SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001911 return getLValue(f, out)->load(out);
1912}
1913
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001914SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001915 SpvId base = this->writeExpression(*swizzle.fBase, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001916 SpvId result = this->nextId();
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001917 size_t count = swizzle.fComponents.size();
ethannicholasb3058bd2016-07-01 08:22:01 -07001918 if (count == 1) {
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001919 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
1920 swizzle.fComponents[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001921 } else {
1922 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001923 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001924 this->writeWord(result, out);
1925 this->writeWord(base, out);
Ethan Nicholase455f652019-09-13 12:52:55 -04001926 SpvId other = base;
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001927 for (int c : swizzle.fComponents) {
Ethan Nicholase455f652019-09-13 12:52:55 -04001928 if (c < 0) {
1929 if (!fConstantZeroOneVector) {
1930 FloatLiteral zero(fContext, -1, 0);
1931 SpvId zeroId = this->writeFloatLiteral(zero);
1932 FloatLiteral one(fContext, -1, 1);
1933 SpvId oneId = this->writeFloatLiteral(one);
1934 SpvId type = this->getType(*fContext.fFloat2_Type);
1935 fConstantZeroOneVector = this->nextId();
1936 this->writeOpCode(SpvOpConstantComposite, 5, fConstantBuffer);
1937 this->writeWord(type, fConstantBuffer);
1938 this->writeWord(fConstantZeroOneVector, fConstantBuffer);
1939 this->writeWord(zeroId, fConstantBuffer);
1940 this->writeWord(oneId, fConstantBuffer);
1941 }
1942 other = fConstantZeroOneVector;
1943 break;
Ethan Nicholasac285b12019-02-12 16:05:18 -05001944 }
Ethan Nicholasac285b12019-02-12 16:05:18 -05001945 }
1946 this->writeWord(other, out);
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001947 for (int component : swizzle.fComponents) {
Ethan Nicholasac285b12019-02-12 16:05:18 -05001948 if (component == SKSL_SWIZZLE_0) {
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001949 this->writeWord(swizzle.fBase->fType.columns(), out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001950 } else if (component == SKSL_SWIZZLE_1) {
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001951 this->writeWord(swizzle.fBase->fType.columns() + 1, out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001952 } else {
1953 this->writeWord(component, out);
1954 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001955 }
1956 }
1957 return result;
1958}
1959
Greg Daniel64773e62016-11-22 09:44:03 -05001960SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1961 const Type& operandType, SpvId lhs,
1962 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001963 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001964 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001965 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001966 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001967 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001968 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001969 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001970 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001971 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001972 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001973 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07001974 } else {
1975 ABORT("invalid operandType: %s", operandType.description().c_str());
1976 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04001977 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001978 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
1979 fDecorationBuffer);
1980 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001981 return result;
1982}
1983
Ethan Nicholas48e24052018-03-14 13:51:39 -04001984SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
1985 OutputStream& out) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05001986 if (operandType.kind() == Type::kVector_Kind) {
1987 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04001988 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05001989 return result;
1990 }
1991 return id;
1992}
1993
Ethan Nicholas68990be2017-07-13 09:36:52 -04001994SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
1995 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04001996 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04001997 OutputStream& out) {
1998 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001999 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002000 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2001 operandType.rows(),
2002 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04002003 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002004 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04002005 1));
2006 SpvId boolType = this->getType(*fContext.fBool_Type);
2007 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04002008 for (int i = 0; i < operandType.columns(); i++) {
2009 SpvId columnL = this->nextId();
2010 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2011 SpvId columnR = this->nextId();
2012 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002013 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002014 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
2015 SpvId merge = this->nextId();
2016 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002017 if (result != 0) {
2018 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002019 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002020 result = next;
2021 }
2022 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002023 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04002024 }
2025 }
2026 return result;
2027}
2028
Ethan Nicholas0df21132018-07-10 09:37:51 -04002029SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
2030 SpvId rhs, SpvOp_ floatOperator,
2031 SpvOp_ intOperator,
2032 OutputStream& out) {
2033 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
2034 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
2035 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2036 operandType.rows(),
2037 1));
2038 SpvId columns[4];
2039 for (int i = 0; i < operandType.columns(); i++) {
2040 SpvId columnL = this->nextId();
2041 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2042 SpvId columnR = this->nextId();
2043 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2044 columns[i] = this->nextId();
2045 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2046 }
2047 SpvId result = this->nextId();
2048 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2049 this->writeWord(this->getType(operandType), out);
2050 this->writeWord(result, out);
2051 for (int i = 0; i < operandType.columns(); i++) {
2052 this->writeWord(columns[i], out);
2053 }
2054 return result;
2055}
2056
Ethan Nicholas49465b42019-04-17 12:22:21 -04002057std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2058 if (type.isInteger()) {
2059 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002060 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002061 else if (type.isFloat()) {
2062 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002063 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002064 ABORT("math is unsupported on type '%s'", type.name().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002065 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002066}
2067
2068SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Token::Kind op,
2069 const Type& rightType, SpvId rhs,
2070 const Type& resultType, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002071 Type tmp("<invalid>");
Ethan Nicholas48e24052018-03-14 13:51:39 -04002072 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002073 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002074 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2075 // handling in SPIR-V
Ethan Nicholas49465b42019-04-17 12:22:21 -04002076 if (this->getActualType(leftType) != this->getActualType(rightType)) {
2077 if (leftType.kind() == Type::kVector_Kind && rightType.isNumber()) {
2078 if (op == Token::SLASH) {
2079 SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
2080 SpvId inverse = this->nextId();
2081 this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
2082 rhs = inverse;
2083 op = Token::STAR;
2084 }
2085 if (op == Token::STAR) {
2086 SpvId result = this->nextId();
2087 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2088 result, lhs, rhs, out);
2089 return result;
2090 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002091 // promote number to vector
2092 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002093 const Type& vecType = leftType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002094 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2095 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002096 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002097 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002098 this->writeWord(rhs, out);
2099 }
2100 rhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002101 operandType = &leftType;
2102 } else if (rightType.kind() == Type::kVector_Kind && leftType.isNumber()) {
2103 if (op == Token::STAR) {
2104 SpvId result = this->nextId();
2105 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2106 result, rhs, lhs, out);
2107 return result;
2108 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002109 // promote number to vector
2110 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002111 const Type& vecType = rightType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002112 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2113 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002114 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002115 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002116 this->writeWord(lhs, out);
2117 }
2118 lhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002119 operandType = &rightType;
2120 } else if (leftType.kind() == Type::kMatrix_Kind) {
2121 SpvOp_ spvop;
2122 if (rightType.kind() == Type::kMatrix_Kind) {
2123 spvop = SpvOpMatrixTimesMatrix;
2124 } else if (rightType.kind() == Type::kVector_Kind) {
2125 spvop = SpvOpMatrixTimesVector;
ethannicholasb3058bd2016-07-01 08:22:01 -07002126 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002127 SkASSERT(rightType.kind() == Type::kScalar_Kind);
2128 spvop = SpvOpMatrixTimesScalar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002129 }
2130 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002131 this->writeInstruction(spvop, this->getType(resultType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002132 return result;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002133 } else if (rightType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002134 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002135 if (leftType.kind() == Type::kVector_Kind) {
2136 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(resultType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002137 lhs, rhs, out);
2138 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002139 SkASSERT(leftType.kind() == Type::kScalar_Kind);
2140 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(resultType), result,
2141 rhs, lhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002142 }
2143 return result;
2144 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002145 SkASSERT(false);
2146 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002147 }
2148 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002149 tmp = this->getActualType(leftType);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002150 operandType = &tmp;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002151 SkASSERT(*operandType == this->getActualType(rightType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002152 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002153 switch (op) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002154 case Token::EQEQ: {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002155 if (operandType->kind() == Type::kMatrix_Kind) {
2156 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002157 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002158 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002159 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002160 const Type* tmpType;
2161 if (operandType->kind() == Type::kVector_Kind) {
2162 tmpType = &fContext.fBool_Type->toCompound(fContext,
2163 operandType->columns(),
2164 operandType->rows());
2165 } else {
2166 tmpType = &resultType;
2167 }
2168 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002169 SpvOpFOrdEqual, SpvOpIEqual,
2170 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002171 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002172 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002173 case Token::NEQ:
Ethan Nicholas68990be2017-07-13 09:36:52 -04002174 if (operandType->kind() == Type::kMatrix_Kind) {
2175 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002176 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002177 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002178 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002179 const Type* tmpType;
2180 if (operandType->kind() == Type::kVector_Kind) {
2181 tmpType = &fContext.fBool_Type->toCompound(fContext,
2182 operandType->columns(),
2183 operandType->rows());
2184 } else {
2185 tmpType = &resultType;
2186 }
2187 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002188 SpvOpFOrdNotEqual, SpvOpINotEqual,
2189 SpvOpINotEqual, SpvOpLogicalNotEqual,
2190 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002191 *operandType, SpvOpAny, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002192 case Token::GT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002193 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002194 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2195 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002196 SpvOpUGreaterThan, SpvOpUndef, out);
2197 case Token::LT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002198 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002199 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002200 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
2201 case Token::GTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002202 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002203 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2204 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002205 SpvOpUGreaterThanEqual, SpvOpUndef, out);
2206 case Token::LTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002207 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002208 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2209 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002210 SpvOpULessThanEqual, SpvOpUndef, out);
2211 case Token::PLUS:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002212 if (leftType.kind() == Type::kMatrix_Kind &&
2213 rightType.kind() == Type::kMatrix_Kind) {
2214 SkASSERT(leftType == rightType);
2215 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002216 SpvOpFAdd, SpvOpIAdd, out);
2217 }
Greg Daniel64773e62016-11-22 09:44:03 -05002218 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002219 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2220 case Token::MINUS:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002221 if (leftType.kind() == Type::kMatrix_Kind &&
2222 rightType.kind() == Type::kMatrix_Kind) {
2223 SkASSERT(leftType == rightType);
2224 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002225 SpvOpFSub, SpvOpISub, out);
2226 }
Greg Daniel64773e62016-11-22 09:44:03 -05002227 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002228 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2229 case Token::STAR:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002230 if (leftType.kind() == Type::kMatrix_Kind &&
2231 rightType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002232 // matrix multiply
2233 SpvId result = this->nextId();
2234 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2235 lhs, rhs, out);
2236 return result;
2237 }
Greg Daniel64773e62016-11-22 09:44:03 -05002238 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002239 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2240 case Token::SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002241 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002242 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002243 case Token::PERCENT:
2244 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2245 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002246 case Token::SHL:
2247 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2248 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2249 SpvOpUndef, out);
2250 case Token::SHR:
2251 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2252 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2253 SpvOpUndef, out);
2254 case Token::BITWISEAND:
2255 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2256 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
2257 case Token::BITWISEOR:
2258 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2259 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
2260 case Token::BITWISEXOR:
2261 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2262 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04002263 case Token::COMMA:
2264 return rhs;
ethannicholasb3058bd2016-07-01 08:22:01 -07002265 default:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002266 SkASSERT(false);
2267 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002268 }
2269}
2270
Ethan Nicholas49465b42019-04-17 12:22:21 -04002271SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
2272 // handle cases where we don't necessarily evaluate both LHS and RHS
2273 switch (b.fOperator) {
2274 case Token::EQ: {
2275 SpvId rhs = this->writeExpression(*b.fRight, out);
2276 this->getLValue(*b.fLeft, out)->store(rhs, out);
2277 return rhs;
2278 }
2279 case Token::LOGICALAND:
2280 return this->writeLogicalAnd(b, out);
2281 case Token::LOGICALOR:
2282 return this->writeLogicalOr(b, out);
2283 default:
2284 break;
2285 }
2286
2287 std::unique_ptr<LValue> lvalue;
2288 SpvId lhs;
2289 if (is_assignment(b.fOperator)) {
2290 lvalue = this->getLValue(*b.fLeft, out);
2291 lhs = lvalue->load(out);
2292 } else {
2293 lvalue = nullptr;
2294 lhs = this->writeExpression(*b.fLeft, out);
2295 }
2296 SpvId rhs = this->writeExpression(*b.fRight, out);
2297 SpvId result = this->writeBinaryExpression(b.fLeft->fType, lhs, remove_assignment(b.fOperator),
2298 b.fRight->fType, rhs, b.fType, out);
2299 if (lvalue) {
2300 lvalue->store(result, out);
2301 }
2302 return result;
2303}
2304
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002305SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002306 SkASSERT(a.fOperator == Token::LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002307 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002308 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2309 SpvId lhs = this->writeExpression(*a.fLeft, out);
2310 SpvId rhsLabel = this->nextId();
2311 SpvId end = this->nextId();
2312 SpvId lhsBlock = fCurrentBlock;
2313 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2314 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2315 this->writeLabel(rhsLabel, out);
2316 SpvId rhs = this->writeExpression(*a.fRight, out);
2317 SpvId rhsBlock = fCurrentBlock;
2318 this->writeInstruction(SpvOpBranch, end, out);
2319 this->writeLabel(end, out);
2320 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002321 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002322 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002323 return result;
2324}
2325
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002326SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002327 SkASSERT(o.fOperator == Token::LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002328 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002329 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2330 SpvId lhs = this->writeExpression(*o.fLeft, out);
2331 SpvId rhsLabel = this->nextId();
2332 SpvId end = this->nextId();
2333 SpvId lhsBlock = fCurrentBlock;
2334 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2335 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2336 this->writeLabel(rhsLabel, out);
2337 SpvId rhs = this->writeExpression(*o.fRight, out);
2338 SpvId rhsBlock = fCurrentBlock;
2339 this->writeInstruction(SpvOpBranch, end, out);
2340 this->writeLabel(end, out);
2341 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002342 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002343 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002344 return result;
2345}
2346
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002347SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002348 SpvId test = this->writeExpression(*t.fTest, out);
Ethan Nicholas0f21c232018-07-23 09:25:40 -04002349 if (t.fIfTrue->fType.columns() == 1 && t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002350 // both true and false are constants, can just use OpSelect
2351 SpvId result = this->nextId();
2352 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2353 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
Greg Daniel64773e62016-11-22 09:44:03 -05002354 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002355 out);
2356 return result;
2357 }
Greg Daniel64773e62016-11-22 09:44:03 -05002358 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002359 // Adreno. Switched to storing the result in a temp variable as glslang does.
2360 SpvId var = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002361 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002362 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002363 SpvId trueLabel = this->nextId();
2364 SpvId falseLabel = this->nextId();
2365 SpvId end = this->nextId();
2366 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2367 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2368 this->writeLabel(trueLabel, out);
2369 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2370 this->writeInstruction(SpvOpBranch, end, out);
2371 this->writeLabel(falseLabel, out);
2372 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2373 this->writeInstruction(SpvOpBranch, end, out);
2374 this->writeLabel(end, out);
2375 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002376 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002377 this->writePrecisionModifier(t.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002378 return result;
2379}
2380
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002381SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002382 if (p.fOperator == Token::MINUS) {
2383 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002384 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002385 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002386 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002387 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002388 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002389 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2390 } else {
2391 ABORT("unsupported prefix expression %s", p.description().c_str());
Brian Salomon23356442018-11-30 15:33:19 -05002392 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002393 this->writePrecisionModifier(p.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002394 return result;
2395 }
2396 switch (p.fOperator) {
2397 case Token::PLUS:
2398 return this->writeExpression(*p.fOperand, out);
2399 case Token::PLUSPLUS: {
2400 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002401 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002402 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2403 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002404 out);
2405 lv->store(result, out);
2406 return result;
2407 }
2408 case Token::MINUSMINUS: {
2409 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002410 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002411 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2412 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002413 out);
2414 lv->store(result, out);
2415 return result;
2416 }
ethannicholas5961bc92016-10-12 06:39:56 -07002417 case Token::LOGICALNOT: {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002418 SkASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002419 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002420 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002421 this->writeExpression(*p.fOperand, out), out);
2422 return result;
2423 }
ethannicholas5961bc92016-10-12 06:39:56 -07002424 case Token::BITWISENOT: {
2425 SpvId result = this->nextId();
2426 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2427 this->writeExpression(*p.fOperand, out), out);
2428 return result;
2429 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002430 default:
2431 ABORT("unsupported prefix expression: %s", p.description().c_str());
2432 }
2433}
2434
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002435SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002436 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2437 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002438 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002439 switch (p.fOperator) {
2440 case Token::PLUSPLUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002441 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002442 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2443 lv->store(temp, out);
2444 return result;
2445 }
2446 case Token::MINUSMINUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002447 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002448 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2449 lv->store(temp, out);
2450 return result;
2451 }
2452 default:
2453 ABORT("unsupported postfix expression %s", p.description().c_str());
2454 }
2455}
2456
ethannicholasf789b382016-08-03 12:43:36 -07002457SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002458 if (b.fValue) {
2459 if (fBoolTrue == 0) {
2460 fBoolTrue = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002461 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002462 fConstantBuffer);
2463 }
2464 return fBoolTrue;
2465 } else {
2466 if (fBoolFalse == 0) {
2467 fBoolFalse = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002468 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002469 fConstantBuffer);
2470 }
2471 return fBoolFalse;
2472 }
2473}
2474
ethannicholasf789b382016-08-03 12:43:36 -07002475SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002476 ConstantType type;
ethannicholasd598f792016-07-25 10:08:54 -07002477 if (i.fType == *fContext.fInt_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002478 type = ConstantType::kInt;
2479 } else if (i.fType == *fContext.fUInt_Type) {
2480 type = ConstantType::kUInt;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002481 } else if (i.fType == *fContext.fShort_Type || i.fType == *fContext.fByte_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002482 type = ConstantType::kShort;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002483 } else if (i.fType == *fContext.fUShort_Type || i.fType == *fContext.fUByte_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002484 type = ConstantType::kUShort;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002485 } else {
2486 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002487 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002488 std::pair<ConstantValue, ConstantType> key(i.fValue, type);
2489 auto entry = fNumberConstants.find(key);
2490 if (entry == fNumberConstants.end()) {
2491 SpvId result = this->nextId();
2492 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
2493 fConstantBuffer);
2494 fNumberConstants[key] = result;
2495 return result;
2496 }
2497 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002498}
2499
ethannicholasf789b382016-08-03 12:43:36 -07002500SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholase1f55022019-02-05 17:17:40 -05002501 if (f.fType != *fContext.fDouble_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002502 ConstantType type;
2503 if (f.fType == *fContext.fHalf_Type) {
2504 type = ConstantType::kHalf;
2505 } else {
2506 type = ConstantType::kFloat;
2507 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002508 float value = (float) f.fValue;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002509 std::pair<ConstantValue, ConstantType> key(f.fValue, type);
2510 auto entry = fNumberConstants.find(key);
2511 if (entry == fNumberConstants.end()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002512 SpvId result = this->nextId();
2513 uint32_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002514 SkASSERT(sizeof(bits) == sizeof(value));
ethannicholasb3058bd2016-07-01 08:22:01 -07002515 memcpy(&bits, &value, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002516 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
ethannicholasb3058bd2016-07-01 08:22:01 -07002517 fConstantBuffer);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002518 fNumberConstants[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002519 return result;
2520 }
2521 return entry->second;
2522 } else {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002523 std::pair<ConstantValue, ConstantType> key(f.fValue, ConstantType::kDouble);
2524 auto entry = fNumberConstants.find(key);
2525 if (entry == fNumberConstants.end()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002526 SpvId result = this->nextId();
2527 uint64_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002528 SkASSERT(sizeof(bits) == sizeof(f.fValue));
ethannicholasb3058bd2016-07-01 08:22:01 -07002529 memcpy(&bits, &f.fValue, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002530 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002531 bits & 0xffffffff, bits >> 32, fConstantBuffer);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002532 fNumberConstants[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002533 return result;
2534 }
2535 return entry->second;
2536 }
2537}
2538
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002539SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002540 SpvId result = fFunctionMap[&f];
Greg Daniel64773e62016-11-22 09:44:03 -05002541 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002542 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002543 this->writeInstruction(SpvOpName, result, f.fName, fNameBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002544 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002545 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002546 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002547 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002548 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002549 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2550 }
2551 return result;
2552}
2553
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002554SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2555 fVariableBuffer.reset();
ethannicholasb3058bd2016-07-01 08:22:01 -07002556 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2557 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002558 StringStream bodyBuffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04002559 this->writeBlock((Block&) *f.fBody, bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002560 write_stringstream(fVariableBuffer, out);
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002561 if (f.fDeclaration.fName == "main") {
2562 write_stringstream(fGlobalInitializersBuffer, out);
2563 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002564 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002565 if (fCurrentBlock) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002566 if (f.fDeclaration.fReturnType == *fContext.fVoid_Type) {
2567 this->writeInstruction(SpvOpReturn, out);
2568 } else {
2569 this->writeInstruction(SpvOpUnreachable, out);
2570 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002571 }
2572 this->writeInstruction(SpvOpFunctionEnd, out);
2573 return result;
2574}
2575
2576void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2577 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002578 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002579 fDecorationBuffer);
2580 }
2581 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002582 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002583 fDecorationBuffer);
2584 }
2585 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002586 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002587 fDecorationBuffer);
2588 }
2589 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002590 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002591 fDecorationBuffer);
2592 }
Greg Daniel64773e62016-11-22 09:44:03 -05002593 if (layout.fInputAttachmentIndex >= 0) {
2594 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2595 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002596 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002597 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002598 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002599 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002600 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002601 fDecorationBuffer);
2602 }
2603}
2604
2605void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2606 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002607 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002608 layout.fLocation, fDecorationBuffer);
2609 }
2610 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002611 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002612 layout.fBinding, fDecorationBuffer);
2613 }
2614 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002615 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002616 layout.fIndex, fDecorationBuffer);
2617 }
2618 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002619 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002620 layout.fSet, fDecorationBuffer);
2621 }
Greg Daniel64773e62016-11-22 09:44:03 -05002622 if (layout.fInputAttachmentIndex >= 0) {
2623 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2624 layout.fInputAttachmentIndex, fDecorationBuffer);
2625 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002626 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002627 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002628 layout.fBuiltin, fDecorationBuffer);
2629 }
2630}
2631
Ethan Nicholas81d15112018-07-13 12:48:50 -04002632static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2633 switch (m.fLayout.fPrimitive) {
2634 case Layout::kPoints_Primitive:
2635 *outSkInCount = 1;
2636 break;
2637 case Layout::kLines_Primitive:
2638 *outSkInCount = 2;
2639 break;
2640 case Layout::kLinesAdjacency_Primitive:
2641 *outSkInCount = 4;
2642 break;
2643 case Layout::kTriangles_Primitive:
2644 *outSkInCount = 3;
2645 break;
2646 case Layout::kTrianglesAdjacency_Primitive:
2647 *outSkInCount = 6;
2648 break;
2649 default:
2650 return;
2651 }
2652}
2653
ethannicholasf789b382016-08-03 12:43:36 -07002654SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas361941e2017-05-30 15:41:07 -04002655 bool isBuffer = (0 != (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag));
Ethan Nicholas39204fd2017-11-27 13:12:30 -05002656 bool pushConstant = (0 != (intf.fVariable.fModifiers.fLayout.fFlags &
2657 Layout::kPushConstant_Flag));
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002658 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2659 MemoryLayout(MemoryLayout::k430_Standard) :
2660 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002661 SpvId result = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002662 const Type* type = &intf.fVariable.fType;
Greg Daniele6ab9982018-08-22 13:56:32 +00002663 if (fProgram.fInputs.fRTHeight) {
2664 SkASSERT(fRTHeightStructId == (SpvId) -1);
2665 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002666 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002667 fRTHeightStructId = result;
2668 fRTHeightFieldIndex = fields.size();
2669 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002670 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002671 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002672 SpvId typeId;
2673 if (intf.fVariable.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2674 for (const auto& e : fProgram) {
2675 if (e.fKind == ProgramElement::kModifiers_Kind) {
2676 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholas81d15112018-07-13 12:48:50 -04002677 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002678 }
2679 }
2680 typeId = this->getType(Type("sk_in", Type::kArray_Kind, intf.fVariable.fType.componentType(),
2681 fSkInCount), memoryLayout);
2682 } else {
2683 typeId = this->getType(*type, memoryLayout);
2684 }
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002685 if (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag) {
2686 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002687 } else if (intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
2688 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002689 }
ethannicholasd598f792016-07-25 10:08:54 -07002690 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002691 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002692 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002693 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002694 Layout layout = intf.fVariable.fModifiers.fLayout;
2695 if (intf.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
2696 layout.fSet = 0;
2697 }
2698 this->writeLayout(layout, result);
ethannicholasd598f792016-07-25 10:08:54 -07002699 fVariableMap[&intf.fVariable] = result;
Greg Daniele6ab9982018-08-22 13:56:32 +00002700 if (fProgram.fInputs.fRTHeight) {
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002701 delete type;
2702 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002703 return result;
2704}
2705
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002706void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002707 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2708}
2709
2710void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2711 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002712 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2713 }
2714}
2715
ethannicholas5961bc92016-10-12 06:39:56 -07002716#define BUILTIN_IGNORE 9999
Greg Daniel64773e62016-11-22 09:44:03 -05002717void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002718 OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002719 for (size_t i = 0; i < decl.fVars.size(); i++) {
2720 if (decl.fVars[i]->fKind == Statement::kNop_Kind) {
2721 continue;
2722 }
2723 const VarDeclaration& varDecl = (VarDeclaration&) *decl.fVars[i];
2724 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002725 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2726 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002727 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Chris Daltonb0fd4b12019-10-29 13:41:22 -06002728 Modifiers::kWriteOnly_Flag |
2729 Modifiers::kCoherent_Flag |
2730 Modifiers::kVolatile_Flag |
2731 Modifiers::kRestrict_Flag)));
ethannicholas5961bc92016-10-12 06:39:56 -07002732 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2733 continue;
2734 }
2735 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2736 kind != Program::kFragment_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002737 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
ethannicholas5961bc92016-10-12 06:39:56 -07002738 continue;
2739 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05002740 if (!var->fReadCount && !var->fWriteCount &&
ethannicholas14fe8cc2016-09-07 13:37:16 -07002741 !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
2742 Modifiers::kOut_Flag |
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002743 Modifiers::kUniform_Flag |
2744 Modifiers::kBuffer_Flag))) {
ethannicholasd598f792016-07-25 10:08:54 -07002745 // variable is dead and not an input / output var (the Vulkan debug layers complain if
2746 // we elide an interface var, even if it's dead)
ethannicholasb3058bd2016-07-01 08:22:01 -07002747 continue;
2748 }
2749 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002750 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002751 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002752 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002753 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002754 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
Stephen Whiteff5d7a22019-07-26 17:42:06 -04002755 if (var->fType.kind() == Type::kSampler_Kind ||
2756 var->fType.kind() == Type::kSeparateSampler_Kind ||
2757 var->fType.kind() == Type::kTexture_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002758 storageClass = SpvStorageClassUniformConstant;
2759 } else {
2760 storageClass = SpvStorageClassUniform;
2761 }
2762 } else {
2763 storageClass = SpvStorageClassPrivate;
2764 }
2765 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002766 fVariableMap[var] = id;
Ethan Nicholas5226b772018-05-03 16:20:41 -04002767 SpvId type;
2768 if (var->fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2769 type = this->getPointerType(Type("sk_in", Type::kArray_Kind,
2770 var->fType.componentType(), fSkInCount),
2771 storageClass);
2772 } else {
2773 type = this->getPointerType(var->fType, storageClass);
2774 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002775 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002776 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002777 this->writePrecisionModifier(var->fType, id);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002778 if (varDecl.fValue) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002779 SkASSERT(!fCurrentBlock);
ethannicholasf789b382016-08-03 12:43:36 -07002780 fCurrentBlock = -1;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002781 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002782 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002783 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002784 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002785 this->writeLayout(var->fModifiers.fLayout, id);
Ethan Nicholas45b0f152017-07-24 14:36:40 -04002786 if (var->fModifiers.fFlags & Modifiers::kFlat_Flag) {
2787 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2788 }
2789 if (var->fModifiers.fFlags & Modifiers::kNoPerspective_Flag) {
2790 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2791 fDecorationBuffer);
2792 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002793 }
2794}
2795
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002796void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002797 for (const auto& stmt : decl.fVars) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002798 SkASSERT(stmt->fKind == Statement::kVarDeclaration_Kind);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002799 VarDeclaration& varDecl = (VarDeclaration&) *stmt;
2800 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002801 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2802 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002803 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002804 Modifiers::kWriteOnly_Flag |
2805 Modifiers::kCoherent_Flag |
2806 Modifiers::kVolatile_Flag |
2807 Modifiers::kRestrict_Flag)));
ethannicholasb3058bd2016-07-01 08:22:01 -07002808 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002809 fVariableMap[var] = id;
2810 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002811 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002812 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002813 if (varDecl.fValue) {
2814 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002815 this->writeInstruction(SpvOpStore, id, value, out);
2816 }
2817 }
2818}
2819
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002820void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002821 switch (s.fKind) {
Ethan Nicholascb670962017-04-20 19:31:52 -04002822 case Statement::kNop_Kind:
2823 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002824 case Statement::kBlock_Kind:
2825 this->writeBlock((Block&) s, out);
2826 break;
2827 case Statement::kExpression_Kind:
2828 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2829 break;
Greg Daniel64773e62016-11-22 09:44:03 -05002830 case Statement::kReturn_Kind:
ethannicholasb3058bd2016-07-01 08:22:01 -07002831 this->writeReturnStatement((ReturnStatement&) s, out);
2832 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002833 case Statement::kVarDeclarations_Kind:
2834 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002835 break;
2836 case Statement::kIf_Kind:
2837 this->writeIfStatement((IfStatement&) s, out);
2838 break;
2839 case Statement::kFor_Kind:
2840 this->writeForStatement((ForStatement&) s, out);
2841 break;
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002842 case Statement::kWhile_Kind:
2843 this->writeWhileStatement((WhileStatement&) s, out);
2844 break;
2845 case Statement::kDo_Kind:
2846 this->writeDoStatement((DoStatement&) s, out);
2847 break;
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002848 case Statement::kSwitch_Kind:
2849 this->writeSwitchStatement((SwitchStatement&) s, out);
2850 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002851 case Statement::kBreak_Kind:
2852 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2853 break;
2854 case Statement::kContinue_Kind:
2855 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2856 break;
2857 case Statement::kDiscard_Kind:
2858 this->writeInstruction(SpvOpKill, out);
2859 break;
2860 default:
2861 ABORT("unsupported statement: %s", s.description().c_str());
2862 }
2863}
2864
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002865void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002866 for (size_t i = 0; i < b.fStatements.size(); i++) {
2867 this->writeStatement(*b.fStatements[i], out);
2868 }
2869}
2870
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002871void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002872 SpvId test = this->writeExpression(*stmt.fTest, out);
2873 SpvId ifTrue = this->nextId();
2874 SpvId ifFalse = this->nextId();
2875 if (stmt.fIfFalse) {
2876 SpvId end = this->nextId();
2877 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2878 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2879 this->writeLabel(ifTrue, out);
2880 this->writeStatement(*stmt.fIfTrue, out);
2881 if (fCurrentBlock) {
2882 this->writeInstruction(SpvOpBranch, end, out);
2883 }
2884 this->writeLabel(ifFalse, out);
2885 this->writeStatement(*stmt.fIfFalse, out);
2886 if (fCurrentBlock) {
2887 this->writeInstruction(SpvOpBranch, end, out);
2888 }
2889 this->writeLabel(end, out);
2890 } else {
2891 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2892 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2893 this->writeLabel(ifTrue, out);
2894 this->writeStatement(*stmt.fIfTrue, out);
2895 if (fCurrentBlock) {
2896 this->writeInstruction(SpvOpBranch, ifFalse, out);
2897 }
2898 this->writeLabel(ifFalse, out);
2899 }
2900}
2901
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002902void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002903 if (f.fInitializer) {
2904 this->writeStatement(*f.fInitializer, out);
2905 }
2906 SpvId header = this->nextId();
2907 SpvId start = this->nextId();
2908 SpvId body = this->nextId();
2909 SpvId next = this->nextId();
2910 fContinueTarget.push(next);
2911 SpvId end = this->nextId();
2912 fBreakTarget.push(end);
2913 this->writeInstruction(SpvOpBranch, header, out);
2914 this->writeLabel(header, out);
2915 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002916 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002917 this->writeLabel(start, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002918 if (f.fTest) {
2919 SpvId test = this->writeExpression(*f.fTest, out);
2920 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2921 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002922 this->writeLabel(body, out);
2923 this->writeStatement(*f.fStatement, out);
2924 if (fCurrentBlock) {
2925 this->writeInstruction(SpvOpBranch, next, out);
2926 }
2927 this->writeLabel(next, out);
2928 if (f.fNext) {
2929 this->writeExpression(*f.fNext, out);
2930 }
2931 this->writeInstruction(SpvOpBranch, header, out);
2932 this->writeLabel(end, out);
2933 fBreakTarget.pop();
2934 fContinueTarget.pop();
2935}
2936
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002937void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002938 SpvId header = this->nextId();
2939 SpvId start = this->nextId();
2940 SpvId body = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04002941 SpvId continueTarget = this->nextId();
2942 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002943 SpvId end = this->nextId();
2944 fBreakTarget.push(end);
2945 this->writeInstruction(SpvOpBranch, header, out);
2946 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04002947 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002948 this->writeInstruction(SpvOpBranch, start, out);
2949 this->writeLabel(start, out);
2950 SpvId test = this->writeExpression(*w.fTest, out);
2951 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2952 this->writeLabel(body, out);
2953 this->writeStatement(*w.fStatement, out);
2954 if (fCurrentBlock) {
Ethan Nicholas0d997662019-04-08 09:46:01 -04002955 this->writeInstruction(SpvOpBranch, continueTarget, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002956 }
Ethan Nicholas0d997662019-04-08 09:46:01 -04002957 this->writeLabel(continueTarget, out);
2958 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002959 this->writeLabel(end, out);
2960 fBreakTarget.pop();
2961 fContinueTarget.pop();
2962}
2963
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002964void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002965 // We believe the do loop code below will work, but Skia doesn't actually use them and
2966 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2967 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2968 // message, simply remove the error call below to see whether our do loop support actually
2969 // works.
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002970 fErrors.error(d.fOffset, "internal error: do loop support has been disabled in SPIR-V, see "
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002971 "SkSLSPIRVCodeGenerator.cpp for details");
2972
2973 SpvId header = this->nextId();
2974 SpvId start = this->nextId();
2975 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04002976 SpvId continueTarget = this->nextId();
2977 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002978 SpvId end = this->nextId();
2979 fBreakTarget.push(end);
2980 this->writeInstruction(SpvOpBranch, header, out);
2981 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04002982 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002983 this->writeInstruction(SpvOpBranch, start, out);
2984 this->writeLabel(start, out);
2985 this->writeStatement(*d.fStatement, out);
2986 if (fCurrentBlock) {
2987 this->writeInstruction(SpvOpBranch, next, out);
2988 }
2989 this->writeLabel(next, out);
2990 SpvId test = this->writeExpression(*d.fTest, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04002991 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
2992 this->writeLabel(continueTarget, out);
2993 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002994 this->writeLabel(end, out);
2995 fBreakTarget.pop();
2996 fContinueTarget.pop();
2997}
2998
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002999void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
3000 SpvId value = this->writeExpression(*s.fValue, out);
3001 std::vector<SpvId> labels;
3002 SpvId end = this->nextId();
3003 SpvId defaultLabel = end;
3004 fBreakTarget.push(end);
3005 int size = 3;
3006 for (const auto& c : s.fCases) {
3007 SpvId label = this->nextId();
3008 labels.push_back(label);
3009 if (c->fValue) {
3010 size += 2;
3011 } else {
3012 defaultLabel = label;
3013 }
3014 }
3015 labels.push_back(end);
3016 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3017 this->writeOpCode(SpvOpSwitch, size, out);
3018 this->writeWord(value, out);
3019 this->writeWord(defaultLabel, out);
3020 for (size_t i = 0; i < s.fCases.size(); ++i) {
3021 if (!s.fCases[i]->fValue) {
3022 continue;
3023 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003024 SkASSERT(s.fCases[i]->fValue->fKind == Expression::kIntLiteral_Kind);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003025 this->writeWord(((IntLiteral&) *s.fCases[i]->fValue).fValue, out);
3026 this->writeWord(labels[i], out);
3027 }
3028 for (size_t i = 0; i < s.fCases.size(); ++i) {
3029 this->writeLabel(labels[i], out);
3030 for (const auto& stmt : s.fCases[i]->fStatements) {
3031 this->writeStatement(*stmt, out);
3032 }
3033 if (fCurrentBlock) {
3034 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3035 }
3036 }
3037 this->writeLabel(end, out);
3038 fBreakTarget.pop();
3039}
3040
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003041void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003042 if (r.fExpression) {
Greg Daniel64773e62016-11-22 09:44:03 -05003043 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003044 out);
3045 } else {
3046 this->writeInstruction(SpvOpReturn, out);
3047 }
3048}
3049
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003050void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003051 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003052 int invocations = 1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003053 for (const auto& e : fProgram) {
3054 if (e.fKind == ProgramElement::kModifiers_Kind) {
3055 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003056 if (m.fFlags & Modifiers::kIn_Flag) {
3057 if (m.fLayout.fInvocations != -1) {
3058 invocations = m.fLayout.fInvocations;
3059 }
3060 SpvId input;
3061 switch (m.fLayout.fPrimitive) {
3062 case Layout::kPoints_Primitive:
3063 input = SpvExecutionModeInputPoints;
3064 break;
3065 case Layout::kLines_Primitive:
3066 input = SpvExecutionModeInputLines;
3067 break;
3068 case Layout::kLinesAdjacency_Primitive:
3069 input = SpvExecutionModeInputLinesAdjacency;
3070 break;
3071 case Layout::kTriangles_Primitive:
3072 input = SpvExecutionModeTriangles;
3073 break;
3074 case Layout::kTrianglesAdjacency_Primitive:
3075 input = SpvExecutionModeInputTrianglesAdjacency;
3076 break;
3077 default:
3078 input = 0;
3079 break;
3080 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003081 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003082 if (input) {
3083 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3084 }
3085 } else if (m.fFlags & Modifiers::kOut_Flag) {
3086 SpvId output;
3087 switch (m.fLayout.fPrimitive) {
3088 case Layout::kPoints_Primitive:
3089 output = SpvExecutionModeOutputPoints;
3090 break;
3091 case Layout::kLineStrip_Primitive:
3092 output = SpvExecutionModeOutputLineStrip;
3093 break;
3094 case Layout::kTriangleStrip_Primitive:
3095 output = SpvExecutionModeOutputTriangleStrip;
3096 break;
3097 default:
3098 output = 0;
3099 break;
3100 }
3101 if (output) {
3102 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3103 }
3104 if (m.fLayout.fMaxVertices != -1) {
3105 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3106 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3107 out);
3108 }
3109 }
3110 }
3111 }
3112 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3113 invocations, out);
3114}
3115
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003116void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003117 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003118 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003119 std::set<SpvId> interfaceVars;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003120 // assign IDs to functions, determine sk_in size
3121 int skInSize = -1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003122 for (const auto& e : program) {
3123 switch (e.fKind) {
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003124 case ProgramElement::kFunction_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003125 FunctionDefinition& f = (FunctionDefinition&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003126 fFunctionMap[&f.fDeclaration] = this->nextId();
3127 break;
3128 }
3129 case ProgramElement::kModifiers_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003130 Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003131 if (m.fFlags & Modifiers::kIn_Flag) {
3132 switch (m.fLayout.fPrimitive) {
3133 case Layout::kPoints_Primitive: // break
3134 case Layout::kLines_Primitive:
3135 skInSize = 1;
3136 break;
3137 case Layout::kLinesAdjacency_Primitive: // break
3138 skInSize = 2;
3139 break;
3140 case Layout::kTriangles_Primitive: // break
3141 case Layout::kTrianglesAdjacency_Primitive:
3142 skInSize = 3;
3143 break;
3144 default:
3145 break;
3146 }
3147 }
3148 break;
3149 }
3150 default:
3151 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003152 }
3153 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003154 for (const auto& e : program) {
3155 if (e.fKind == ProgramElement::kInterfaceBlock_Kind) {
3156 InterfaceBlock& intf = (InterfaceBlock&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003157 if (SK_IN_BUILTIN == intf.fVariable.fModifiers.fLayout.fBuiltin) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003158 SkASSERT(skInSize != -1);
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003159 intf.fSizes.emplace_back(new IntLiteral(fContext, -1, skInSize));
3160 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003161 SpvId id = this->writeInterfaceBlock(intf);
Ethan Nicholas16c11962018-03-16 12:20:54 -04003162 if (((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
3163 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) &&
3164 intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003165 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003166 }
3167 }
3168 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003169 for (const auto& e : program) {
3170 if (e.fKind == ProgramElement::kVar_Kind) {
3171 this->writeGlobalVars(program.fKind, ((VarDeclarations&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003172 }
3173 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003174 for (const auto& e : program) {
3175 if (e.fKind == ProgramElement::kFunction_Kind) {
3176 this->writeFunction(((FunctionDefinition&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003177 }
3178 }
ethannicholasd598f792016-07-25 10:08:54 -07003179 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003180 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07003181 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003182 main = entry.first;
3183 }
3184 }
Ethan Nicholas1a668d22019-04-18 10:37:40 -04003185 if (!main) {
3186 fErrors.error(0, "program does not contain a main() function");
3187 return;
3188 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003189 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003190 const Variable* var = entry.first;
Greg Daniel64773e62016-11-22 09:44:03 -05003191 if (var->fStorage == Variable::kGlobal_Storage &&
Ethan Nicholas16c11962018-03-16 12:20:54 -04003192 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
Ethan Nicholasd23c8192018-09-26 17:01:24 -04003193 (var->fModifiers.fFlags & Modifiers::kOut_Flag))) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003194 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003195 }
3196 }
3197 this->writeCapabilities(out);
3198 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3199 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003200 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->fName.fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003201 (int32_t) interfaceVars.size(), out);
3202 switch (program.fKind) {
3203 case Program::kVertex_Kind:
3204 this->writeWord(SpvExecutionModelVertex, out);
3205 break;
3206 case Program::kFragment_Kind:
3207 this->writeWord(SpvExecutionModelFragment, out);
3208 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003209 case Program::kGeometry_Kind:
3210 this->writeWord(SpvExecutionModelGeometry, out);
3211 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003212 default:
3213 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003214 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003215 SpvId entryPoint = fFunctionMap[main];
3216 this->writeWord(entryPoint, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003217 this->writeString(main->fName.fChars, main->fName.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003218 for (int var : interfaceVars) {
3219 this->writeWord(var, out);
3220 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003221 if (program.fKind == Program::kGeometry_Kind) {
3222 this->writeGeometryShaderExecutionMode(entryPoint, out);
3223 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003224 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003225 this->writeInstruction(SpvOpExecutionMode,
3226 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003227 SpvExecutionModeOriginUpperLeft,
3228 out);
3229 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003230 for (const auto& e : program) {
3231 if (e.fKind == ProgramElement::kExtension_Kind) {
3232 this->writeInstruction(SpvOpSourceExtension, ((Extension&) e).fName.c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003233 }
3234 }
Greg Daniel64773e62016-11-22 09:44:03 -05003235
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003236 write_stringstream(fExtraGlobalsBuffer, out);
3237 write_stringstream(fNameBuffer, out);
3238 write_stringstream(fDecorationBuffer, out);
3239 write_stringstream(fConstantBuffer, out);
3240 write_stringstream(fExternalFunctionsBuffer, out);
3241 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003242}
3243
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003244bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003245 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003246 this->writeWord(SpvMagicNumber, *fOut);
3247 this->writeWord(SpvVersion, *fOut);
3248 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003249 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003250 this->writeInstructions(fProgram, buffer);
3251 this->writeWord(fIdCount, *fOut);
3252 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003253 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003254 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003255}
3256
3257}