blob: 4103592581ef4dd36038e8f54aca70ad84640bcd [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 }
John Stiles8c578662020-06-01 15:32:47 +0000155 return type == *context.fFloat_Type || type == *context.fHalf_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700156}
157
ethannicholasd598f792016-07-25 10:08:54 -0700158static bool is_signed(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700159 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700160 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700161 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400162 return type == *context.fInt_Type || type == *context.fShort_Type ||
163 type == *context.fByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700164}
165
ethannicholasd598f792016-07-25 10:08:54 -0700166static bool is_unsigned(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700167 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700168 return is_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700169 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400170 return type == *context.fUInt_Type || type == *context.fUShort_Type ||
171 type == *context.fUByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700172}
173
ethannicholasd598f792016-07-25 10:08:54 -0700174static bool is_bool(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700175 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700176 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700177 }
ethannicholasd598f792016-07-25 10:08:54 -0700178 return type == *context.fBool_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700179}
180
ethannicholasd598f792016-07-25 10:08:54 -0700181static bool is_out(const Variable& var) {
182 return (var.fModifiers.fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700183}
184
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400185void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400186 SkASSERT(opCode != SpvOpLoad || &out != &fConstantBuffer);
187 SkASSERT(opCode != SpvOpUndef);
ethannicholasb3058bd2016-07-01 08:22:01 -0700188 switch (opCode) {
189 case SpvOpReturn: // fall through
190 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700191 case SpvOpKill: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700192 case SpvOpBranch: // fall through
193 case SpvOpBranchConditional:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400194 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700195 fCurrentBlock = 0;
196 break;
197 case SpvOpConstant: // fall through
198 case SpvOpConstantTrue: // fall through
199 case SpvOpConstantFalse: // fall through
200 case SpvOpConstantComposite: // fall through
201 case SpvOpTypeVoid: // fall through
202 case SpvOpTypeInt: // fall through
203 case SpvOpTypeFloat: // fall through
204 case SpvOpTypeBool: // fall through
205 case SpvOpTypeVector: // fall through
206 case SpvOpTypeMatrix: // fall through
207 case SpvOpTypeArray: // fall through
208 case SpvOpTypePointer: // fall through
209 case SpvOpTypeFunction: // fall through
210 case SpvOpTypeRuntimeArray: // fall through
211 case SpvOpTypeStruct: // fall through
212 case SpvOpTypeImage: // fall through
213 case SpvOpTypeSampledImage: // fall through
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400214 case SpvOpTypeSampler: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700215 case SpvOpVariable: // fall through
216 case SpvOpFunction: // fall through
217 case SpvOpFunctionParameter: // fall through
218 case SpvOpFunctionEnd: // fall through
219 case SpvOpExecutionMode: // fall through
220 case SpvOpMemoryModel: // fall through
221 case SpvOpCapability: // fall through
222 case SpvOpExtInstImport: // fall through
223 case SpvOpEntryPoint: // fall through
224 case SpvOpSource: // fall through
225 case SpvOpSourceExtension: // fall through
226 case SpvOpName: // fall through
227 case SpvOpMemberName: // fall through
228 case SpvOpDecorate: // fall through
229 case SpvOpMemberDecorate:
230 break;
231 default:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400232 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700233 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700234 this->writeWord((length << 16) | opCode, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700235}
236
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400237void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700238 fCurrentBlock = label;
239 this->writeInstruction(SpvOpLabel, label, out);
240}
241
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400242void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700243 this->writeOpCode(opCode, 1, out);
244}
245
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400246void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700247 this->writeOpCode(opCode, 2, out);
248 this->writeWord(word1, out);
249}
250
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700251void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputStream& out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400252 out.write(string, length);
ethannicholasb3058bd2016-07-01 08:22:01 -0700253 switch (length % 4) {
254 case 1:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500255 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400256 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700257 case 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500258 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400259 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700260 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500261 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700262 break;
263 default:
264 this->writeWord(0, out);
265 }
266}
267
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700268void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out) {
269 this->writeOpCode(opCode, 1 + (string.fLength + 4) / 4, out);
270 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700271}
272
273
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700274void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400275 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700276 this->writeOpCode(opCode, 2 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700277 this->writeWord(word1, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700278 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700279}
280
Greg Daniel64773e62016-11-22 09:44:03 -0500281void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700282 StringFragment string, OutputStream& out) {
283 this->writeOpCode(opCode, 3 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700284 this->writeWord(word1, out);
285 this->writeWord(word2, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700286 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700287}
288
Greg Daniel64773e62016-11-22 09:44:03 -0500289void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400290 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700291 this->writeOpCode(opCode, 3, out);
292 this->writeWord(word1, out);
293 this->writeWord(word2, out);
294}
295
Greg Daniel64773e62016-11-22 09:44:03 -0500296void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400297 int32_t word3, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700298 this->writeOpCode(opCode, 4, out);
299 this->writeWord(word1, out);
300 this->writeWord(word2, out);
301 this->writeWord(word3, out);
302}
303
Greg Daniel64773e62016-11-22 09:44:03 -0500304void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400305 int32_t word3, int32_t word4, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700306 this->writeOpCode(opCode, 5, out);
307 this->writeWord(word1, out);
308 this->writeWord(word2, out);
309 this->writeWord(word3, out);
310 this->writeWord(word4, out);
311}
312
Greg Daniel64773e62016-11-22 09:44:03 -0500313void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
314 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400315 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700316 this->writeOpCode(opCode, 6, out);
317 this->writeWord(word1, out);
318 this->writeWord(word2, out);
319 this->writeWord(word3, out);
320 this->writeWord(word4, out);
321 this->writeWord(word5, out);
322}
323
Greg Daniel64773e62016-11-22 09:44:03 -0500324void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700325 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400326 int32_t word6, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700327 this->writeOpCode(opCode, 7, out);
328 this->writeWord(word1, out);
329 this->writeWord(word2, out);
330 this->writeWord(word3, out);
331 this->writeWord(word4, out);
332 this->writeWord(word5, out);
333 this->writeWord(word6, out);
334}
335
Greg Daniel64773e62016-11-22 09:44:03 -0500336void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700337 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400338 int32_t word6, int32_t word7, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700339 this->writeOpCode(opCode, 8, out);
340 this->writeWord(word1, out);
341 this->writeWord(word2, out);
342 this->writeWord(word3, out);
343 this->writeWord(word4, out);
344 this->writeWord(word5, out);
345 this->writeWord(word6, out);
346 this->writeWord(word7, out);
347}
348
Greg Daniel64773e62016-11-22 09:44:03 -0500349void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700350 int32_t word3, int32_t word4, int32_t word5,
351 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400352 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700353 this->writeOpCode(opCode, 9, out);
354 this->writeWord(word1, out);
355 this->writeWord(word2, out);
356 this->writeWord(word3, out);
357 this->writeWord(word4, out);
358 this->writeWord(word5, out);
359 this->writeWord(word6, out);
360 this->writeWord(word7, out);
361 this->writeWord(word8, out);
362}
363
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400364void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700365 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
366 if (fCapabilities & bit) {
367 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
368 }
369 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400370 if (fProgram.fKind == Program::kGeometry_Kind) {
371 this->writeInstruction(SpvOpCapability, SpvCapabilityGeometry, out);
372 }
Ethan Nicholas81d15112018-07-13 12:48:50 -0400373 else {
374 this->writeInstruction(SpvOpCapability, SpvCapabilityShader, out);
375 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700376}
377
378SpvId SPIRVCodeGenerator::nextId() {
379 return fIdCount++;
380}
381
Ethan Nicholas19671772016-11-28 16:30:17 -0500382void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
383 SpvId resultId) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700384 this->writeInstruction(SpvOpName, resultId, type.name().c_str(), fNameBuffer);
385 // go ahead and write all of the field types, so we don't inadvertently write them while we're
386 // in the middle of writing the struct instruction
387 std::vector<SpvId> types;
388 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500389 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700390 }
391 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
392 this->writeWord(resultId, fConstantBuffer);
393 for (SpvId id : types) {
394 this->writeWord(id, fConstantBuffer);
395 }
396 size_t offset = 0;
397 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400398 const Type::Field& field = type.fields()[i];
399 size_t size = memoryLayout.size(*field.fType);
400 size_t alignment = memoryLayout.alignment(*field.fType);
401 const Layout& fieldLayout = field.fModifiers.fLayout;
Ethan Nicholas19671772016-11-28 16:30:17 -0500402 if (fieldLayout.fOffset >= 0) {
Greg Danieldbd44c72017-01-24 15:12:12 -0500403 if (fieldLayout.fOffset < (int) offset) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700404 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400405 "offset of field '" + field.fName + "' must be at "
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500406 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -0500407 }
408 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700409 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400410 "offset of field '" + field.fName + "' must be a multiple"
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500411 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -0500412 }
413 offset = fieldLayout.fOffset;
414 } else {
415 size_t mod = offset % alignment;
416 if (mod) {
417 offset += alignment - mod;
418 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700419 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400420 this->writeInstruction(SpvOpMemberName, resultId, i, field.fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500421 this->writeLayout(fieldLayout, resultId, i);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400422 if (field.fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -0500423 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700424 (SpvId) offset, fDecorationBuffer);
425 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400426 if (field.fType->kind() == Type::kMatrix_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -0500427 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -0700428 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500429 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400430 (SpvId) memoryLayout.stride(*field.fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800431 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700432 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400433 if (!field.fType->highPrecision()) {
434 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i,
435 SpvDecorationRelaxedPrecision, fDecorationBuffer);
436 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700437 offset += size;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400438 Type::Kind kind = field.fType->kind();
ethannicholasb3058bd2016-07-01 08:22:01 -0700439 if ((kind == Type::kArray_Kind || kind == Type::kStruct_Kind) && offset % alignment != 0) {
440 offset += alignment - offset % alignment;
441 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700442 }
443}
444
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400445Type SPIRVCodeGenerator::getActualType(const Type& type) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500446 if (type.isFloat()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400447 return *fContext.fFloat_Type;
448 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500449 if (type.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400450 return *fContext.fInt_Type;
451 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500452 if (type.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400453 return *fContext.fUInt_Type;
454 }
455 if (type.kind() == Type::kMatrix_Kind || type.kind() == Type::kVector_Kind) {
456 if (type.componentType() == *fContext.fHalf_Type) {
457 return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
458 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400459 if (type.componentType() == *fContext.fShort_Type ||
460 type.componentType() == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400461 return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
462 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400463 if (type.componentType() == *fContext.fUShort_Type ||
464 type.componentType() == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400465 return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
466 }
467 }
468 return type;
469}
470
ethannicholasb3058bd2016-07-01 08:22:01 -0700471SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800472 return this->getType(type, fDefaultLayout);
473}
474
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400475SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
476 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400477 String key = type.name() + to_string((int) layout.fStd);
ethannicholas8ac838d2016-11-22 08:39:36 -0800478 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700479 if (entry == fTypeMap.end()) {
480 SpvId result = this->nextId();
481 switch (type.kind()) {
482 case Type::kScalar_Kind:
ethannicholasd598f792016-07-25 10:08:54 -0700483 if (type == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700484 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500485 } else if (type == *fContext.fInt_Type || type == *fContext.fShort_Type ||
486 type == *fContext.fIntLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700487 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500488 } else if (type == *fContext.fUInt_Type || type == *fContext.fUShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700489 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500490 } else if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type ||
491 type == *fContext.fFloatLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700492 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700493 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400494 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700495 }
496 break;
497 case Type::kVector_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500498 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800499 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700500 type.columns(), fConstantBuffer);
501 break;
502 case Type::kMatrix_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500503 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800504 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700505 type.columns(), fConstantBuffer);
506 break;
507 case Type::kStruct_Kind:
ethannicholas8ac838d2016-11-22 08:39:36 -0800508 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700509 break;
510 case Type::kArray_Kind: {
511 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700512 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500513 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800514 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700515 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500516 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400517 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800518 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700519 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400520 SkASSERT(false); // we shouldn't have any runtime-sized arrays right now
Greg Daniel64773e62016-11-22 09:44:03 -0500521 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800522 this->getType(type.componentType(), layout),
523 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400524 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
525 (int32_t) layout.stride(type),
526 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700527 }
528 break;
529 }
530 case Type::kSampler_Kind: {
Greg Daniel64773e62016-11-22 09:44:03 -0500531 SpvId image = result;
532 if (SpvDimSubpassData != type.dimensions()) {
Stephen White792e2302019-08-09 13:33:51 -0400533 image = this->getType(type.textureType(), layout);
Greg Daniel64773e62016-11-22 09:44:03 -0500534 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400535 if (SpvDimBuffer == type.dimensions()) {
536 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
537 }
Greg Daniel64773e62016-11-22 09:44:03 -0500538 if (SpvDimSubpassData != type.dimensions()) {
539 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
540 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700541 break;
542 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400543 case Type::kSeparateSampler_Kind: {
544 this->writeInstruction(SpvOpTypeSampler, result, fConstantBuffer);
545 break;
546 }
547 case Type::kTexture_Kind: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400548 this->writeInstruction(SpvOpTypeImage, result,
549 this->getType(*fContext.fFloat_Type, layout),
Stephen White792e2302019-08-09 13:33:51 -0400550 type.dimensions(), type.isDepth(), type.isArrayed(),
551 type.isMultisampled(), type.isSampled() ? 1 : 2,
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400552 SpvImageFormatUnknown, fConstantBuffer);
553 fImageTypeMap[key] = result;
554 break;
555 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700556 default:
ethannicholasd598f792016-07-25 10:08:54 -0700557 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700558 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
559 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500560#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700561 ABORT("invalid type: %s", type.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500562#endif
ethannicholasb3058bd2016-07-01 08:22:01 -0700563 }
564 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800565 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700566 return result;
567 }
568 return entry->second;
569}
570
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400571SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400572 SkASSERT(type.kind() == Type::kSampler_Kind);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400573 this->getType(type);
574 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400575 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400576 return fImageTypeMap[key];
577}
578
ethannicholasd598f792016-07-25 10:08:54 -0700579SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Brian Osmanc4f937b2020-03-25 15:39:07 -0400580 String key = to_string(this->getType(function.fReturnType)) + "(";
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400581 String separator;
ethannicholasd598f792016-07-25 10:08:54 -0700582 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700583 key += separator;
584 separator = ", ";
Brian Osmanc4f937b2020-03-25 15:39:07 -0400585 key += to_string(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700586 }
587 key += ")";
588 auto entry = fTypeMap.find(key);
589 if (entry == fTypeMap.end()) {
590 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -0700591 int32_t length = 3 + (int32_t) function.fParameters.size();
592 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700593 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -0700594 for (size_t i = 0; i < function.fParameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500595 // glslang seems to treat all function arguments as pointers whether they need to be or
596 // not. I was initially puzzled by this until I ran bizarre failures with certain
597 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700598 // failure case:
599 //
600 // void sphere(float x) {
601 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500602 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700603 // void map() {
604 // sphere(1.0);
605 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500606 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700607 // void main() {
608 // for (int i = 0; i < 1; i++) {
609 // map();
610 // }
611 // }
612 //
Greg Daniel64773e62016-11-22 09:44:03 -0500613 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
614 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700615 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
616 // the spec makes this make sense.
617// if (is_out(function->fParameters[i])) {
ethannicholasd598f792016-07-25 10:08:54 -0700618 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -0700619 SpvStorageClassFunction));
620// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700621// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700622// }
623 }
624 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
625 this->writeWord(result, fConstantBuffer);
626 this->writeWord(returnType, fConstantBuffer);
627 for (SpvId id : parameterTypes) {
628 this->writeWord(id, fConstantBuffer);
629 }
630 fTypeMap[key] = result;
631 return result;
632 }
633 return entry->second;
634}
635
ethannicholas8ac838d2016-11-22 08:39:36 -0800636SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
637 return this->getPointerType(type, fDefaultLayout, storageClass);
638}
639
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400640SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700641 SpvStorageClass_ storageClass) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400642 Type type = this->getActualType(rawType);
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500643 String key = type.displayName() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700644 auto entry = fTypeMap.find(key);
645 if (entry == fTypeMap.end()) {
646 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500647 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700648 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700649 fTypeMap[key] = result;
650 return result;
651 }
652 return entry->second;
653}
654
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400655SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700656 switch (expr.fKind) {
657 case Expression::kBinary_Kind:
658 return this->writeBinaryExpression((BinaryExpression&) expr, out);
659 case Expression::kBoolLiteral_Kind:
660 return this->writeBoolLiteral((BoolLiteral&) expr);
661 case Expression::kConstructor_Kind:
662 return this->writeConstructor((Constructor&) expr, out);
663 case Expression::kIntLiteral_Kind:
664 return this->writeIntLiteral((IntLiteral&) expr);
665 case Expression::kFieldAccess_Kind:
666 return this->writeFieldAccess(((FieldAccess&) expr), out);
667 case Expression::kFloatLiteral_Kind:
668 return this->writeFloatLiteral(((FloatLiteral&) expr));
669 case Expression::kFunctionCall_Kind:
670 return this->writeFunctionCall((FunctionCall&) expr, out);
671 case Expression::kPrefix_Kind:
672 return this->writePrefixExpression((PrefixExpression&) expr, out);
673 case Expression::kPostfix_Kind:
674 return this->writePostfixExpression((PostfixExpression&) expr, out);
675 case Expression::kSwizzle_Kind:
676 return this->writeSwizzle((Swizzle&) expr, out);
677 case Expression::kVariableReference_Kind:
678 return this->writeVariableReference((VariableReference&) expr, out);
679 case Expression::kTernary_Kind:
680 return this->writeTernaryExpression((TernaryExpression&) expr, out);
681 case Expression::kIndex_Kind:
682 return this->writeIndexExpression((IndexExpression&) expr, out);
683 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500684#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700685 ABORT("unsupported expression: %s", expr.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500686#endif
687 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700688 }
689 return -1;
690}
691
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400692SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700693 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400694 SkASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -0700695 int32_t intrinsicId;
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400696 if (c.fArguments.size() > 0) {
697 const Type& type = c.fArguments[0]->fType;
698 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
699 intrinsicId = std::get<1>(intrinsic->second);
700 } else if (is_signed(fContext, type)) {
701 intrinsicId = std::get<2>(intrinsic->second);
702 } else if (is_unsigned(fContext, type)) {
703 intrinsicId = std::get<3>(intrinsic->second);
704 } else if (is_bool(fContext, type)) {
705 intrinsicId = std::get<4>(intrinsic->second);
706 } else {
707 intrinsicId = std::get<1>(intrinsic->second);
708 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700709 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400710 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700711 }
712 switch (std::get<0>(intrinsic->second)) {
713 case kGLSL_STD_450_IntrinsicKind: {
714 SpvId result = this->nextId();
715 std::vector<SpvId> arguments;
716 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400717 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
718 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
719 } else {
720 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
721 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700722 }
723 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700724 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700725 this->writeWord(result, out);
726 this->writeWord(fGLSLExtendedInstructions, out);
727 this->writeWord(intrinsicId, out);
728 for (SpvId id : arguments) {
729 this->writeWord(id, out);
730 }
731 return result;
732 }
733 case kSPIRV_IntrinsicKind: {
734 SpvId result = this->nextId();
735 std::vector<SpvId> arguments;
736 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400737 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
738 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
739 } else {
740 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
741 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700742 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400743 if (c.fType != *fContext.fVoid_Type) {
744 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
745 this->writeWord(this->getType(c.fType), out);
746 this->writeWord(result, out);
747 } else {
748 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
749 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700750 for (SpvId id : arguments) {
751 this->writeWord(id, out);
752 }
753 return result;
754 }
755 case kSpecial_IntrinsicKind:
756 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
757 default:
758 ABORT("unsupported intrinsic kind");
759 }
760}
761
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500762std::vector<SpvId> SPIRVCodeGenerator::vectorize(
763 const std::vector<std::unique_ptr<Expression>>& args,
764 OutputStream& out) {
765 int vectorSize = 0;
766 for (const auto& a : args) {
767 if (a->fType.kind() == Type::kVector_Kind) {
768 if (vectorSize) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400769 SkASSERT(a->fType.columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500770 }
771 else {
772 vectorSize = a->fType.columns();
773 }
774 }
775 }
776 std::vector<SpvId> result;
777 for (const auto& a : args) {
778 SpvId raw = this->writeExpression(*a, out);
779 if (vectorSize && a->fType.kind() == Type::kScalar_Kind) {
780 SpvId vector = this->nextId();
781 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
782 this->writeWord(this->getType(a->fType.toCompound(fContext, vectorSize, 1)), out);
783 this->writeWord(vector, out);
784 for (int i = 0; i < vectorSize; i++) {
785 this->writeWord(raw, out);
786 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400787 this->writePrecisionModifier(a->fType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500788 result.push_back(vector);
789 } else {
790 result.push_back(raw);
791 }
792 }
793 return result;
794}
795
796void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
797 SpvId signedInst, SpvId unsignedInst,
798 const std::vector<SpvId>& args,
799 OutputStream& out) {
800 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
801 this->writeWord(this->getType(type), out);
802 this->writeWord(id, out);
803 this->writeWord(fGLSLExtendedInstructions, out);
804
805 if (is_float(fContext, type)) {
806 this->writeWord(floatInst, out);
807 } else if (is_signed(fContext, type)) {
808 this->writeWord(signedInst, out);
809 } else if (is_unsigned(fContext, type)) {
810 this->writeWord(unsignedInst, out);
811 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400812 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500813 }
814 for (SpvId a : args) {
815 this->writeWord(a, out);
816 }
817}
818
Greg Daniel64773e62016-11-22 09:44:03 -0500819SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400820 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700821 SpvId result = this->nextId();
822 switch (kind) {
823 case kAtan_SpecialIntrinsic: {
824 std::vector<SpvId> arguments;
825 for (size_t i = 0; i < c.fArguments.size(); i++) {
826 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
827 }
828 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700829 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700830 this->writeWord(result, out);
831 this->writeWord(fGLSLExtendedInstructions, out);
832 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
833 for (SpvId id : arguments) {
834 this->writeWord(id, out);
835 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400836 break;
837 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400838 case kSampledImage_SpecialIntrinsic: {
839 SkASSERT(2 == c.fArguments.size());
840 SpvId img = this->writeExpression(*c.fArguments[0], out);
841 SpvId sampler = this->writeExpression(*c.fArguments[1], out);
842 this->writeInstruction(SpvOpSampledImage,
843 this->getType(c.fType),
844 result,
845 img,
846 sampler,
847 out);
848 break;
849 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400850 case kSubpassLoad_SpecialIntrinsic: {
851 SpvId img = this->writeExpression(*c.fArguments[0], out);
852 std::vector<std::unique_ptr<Expression>> args;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700853 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
854 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
855 Constructor ctor(-1, *fContext.fFloat2_Type, std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400856 SpvId coords = this->writeConstantVector(ctor);
857 if (1 == c.fArguments.size()) {
858 this->writeInstruction(SpvOpImageRead,
859 this->getType(c.fType),
860 result,
861 img,
862 coords,
863 out);
864 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400865 SkASSERT(2 == c.fArguments.size());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400866 SpvId sample = this->writeExpression(*c.fArguments[1], out);
867 this->writeInstruction(SpvOpImageRead,
868 this->getType(c.fType),
869 result,
870 img,
871 coords,
872 SpvImageOperandsSampleMask,
873 sample,
874 out);
875 }
876 break;
877 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700878 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500879 SpvOp_ op = SpvOpImageSampleImplicitLod;
880 switch (c.fArguments[0]->fType.dimensions()) {
881 case SpvDim1D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400882 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500883 op = SpvOpImageSampleProjImplicitLod;
884 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400885 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500886 }
887 break;
888 case SpvDim2D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400889 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500890 op = SpvOpImageSampleProjImplicitLod;
891 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400892 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500893 }
894 break;
895 case SpvDim3D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400896 if (c.fArguments[1]->fType == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500897 op = SpvOpImageSampleProjImplicitLod;
898 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400899 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500900 }
901 break;
902 case SpvDimCube: // fall through
903 case SpvDimRect: // fall through
904 case SpvDimBuffer: // fall through
905 case SpvDimSubpassData:
906 break;
907 }
ethannicholasd598f792016-07-25 10:08:54 -0700908 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700909 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
910 SpvId uv = this->writeExpression(*c.fArguments[1], out);
911 if (c.fArguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500912 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700913 SpvImageOperandsBiasMask,
914 this->writeExpression(*c.fArguments[2], out),
915 out);
916 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400917 SkASSERT(c.fArguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500918 if (fProgram.fSettings.fSharpenTextures) {
919 FloatLiteral lodBias(fContext, -1, -0.5);
920 this->writeInstruction(op, type, result, sampler, uv,
921 SpvImageOperandsBiasMask,
922 this->writeFloatLiteral(lodBias),
923 out);
924 } else {
925 this->writeInstruction(op, type, result, sampler, uv,
926 out);
927 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700928 }
929 break;
930 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500931 case kMod_SpecialIntrinsic: {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500932 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400933 SkASSERT(args.size() == 2);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500934 const Type& operandType = c.fArguments[0]->fType;
935 SpvOp_ op;
936 if (is_float(fContext, operandType)) {
937 op = SpvOpFMod;
938 } else if (is_signed(fContext, operandType)) {
939 op = SpvOpSMod;
940 } else if (is_unsigned(fContext, operandType)) {
941 op = SpvOpUMod;
942 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400943 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500944 return 0;
945 }
946 this->writeOpCode(op, 5, out);
947 this->writeWord(this->getType(operandType), out);
948 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500949 this->writeWord(args[0], out);
950 this->writeWord(args[1], out);
951 break;
952 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700953 case kDFdy_SpecialIntrinsic: {
954 SpvId fn = this->writeExpression(*c.fArguments[0], out);
955 this->writeOpCode(SpvOpDPdy, 4, out);
956 this->writeWord(this->getType(c.fType), out);
957 this->writeWord(result, out);
958 this->writeWord(fn, out);
959 if (fProgram.fSettings.fFlipY) {
960 // Flipping Y also negates the Y derivatives.
961 SpvId flipped = this->nextId();
962 this->writeInstruction(SpvOpFNegate, this->getType(c.fType), flipped, result, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -0400963 this->writePrecisionModifier(c.fType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700964 return flipped;
965 }
966 break;
967 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500968 case kClamp_SpecialIntrinsic: {
969 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400970 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500971 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
972 GLSLstd450UClamp, args, out);
973 break;
974 }
975 case kMax_SpecialIntrinsic: {
976 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400977 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500978 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMax, GLSLstd450SMax,
979 GLSLstd450UMax, args, out);
980 break;
981 }
982 case kMin_SpecialIntrinsic: {
983 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400984 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500985 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMin, GLSLstd450SMin,
986 GLSLstd450UMin, args, out);
987 break;
988 }
989 case kMix_SpecialIntrinsic: {
990 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400991 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500992 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMix, SpvOpUndef,
993 SpvOpUndef, args, out);
994 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500995 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400996 case kSaturate_SpecialIntrinsic: {
997 SkASSERT(c.fArguments.size() == 1);
998 std::vector<std::unique_ptr<Expression>> finalArgs;
999 finalArgs.push_back(c.fArguments[0]->clone());
1000 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 0));
1001 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 1));
1002 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
1003 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
1004 GLSLstd450UClamp, spvArgs, out);
1005 break;
1006 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001007 }
1008 return result;
1009}
1010
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001011SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001012 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07001013 if (entry == fFunctionMap.end()) {
1014 return this->writeIntrinsicCall(c, out);
1015 }
1016 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001017 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
ethannicholasb3058bd2016-07-01 08:22:01 -07001018 std::vector<SpvId> arguments;
1019 for (size_t i = 0; i < c.fArguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001020 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001021 // passed directly
1022 SpvId tmpVar;
1023 // if we need a temporary var to store this argument, this is the value to store in the var
1024 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -07001025 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001026 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
1027 SpvId ptr = lv->getPointer();
1028 if (ptr) {
1029 arguments.push_back(ptr);
1030 continue;
1031 } else {
1032 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1033 // copy it into a temp, call the function, read the value out of the temp, and then
1034 // update the lvalue.
1035 tmpValueId = lv->load(out);
1036 tmpVar = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001037 lvalues.push_back(std::make_tuple(tmpVar, &c.fArguments[i]->fType, std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001038 }
1039 } else {
1040 // see getFunctionType for an explanation of why we're always using pointer parameters
1041 tmpValueId = this->writeExpression(*c.fArguments[i], out);
1042 tmpVar = this->nextId();
1043 }
Greg Daniel64773e62016-11-22 09:44:03 -05001044 this->writeInstruction(SpvOpVariable,
1045 this->getPointerType(c.fArguments[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -07001046 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001047 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001048 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001049 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001050 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1051 arguments.push_back(tmpVar);
1052 }
1053 SpvId result = this->nextId();
1054 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001055 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001056 this->writeWord(result, out);
1057 this->writeWord(entry->second, out);
1058 for (SpvId id : arguments) {
1059 this->writeWord(id, out);
1060 }
1061 // now that the call is complete, we may need to update some lvalues with the new values of out
1062 // arguments
1063 for (const auto& tuple : lvalues) {
1064 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001065 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1066 out);
1067 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001068 std::get<2>(tuple)->store(load, out);
1069 }
1070 return result;
1071}
1072
ethannicholasf789b382016-08-03 12:43:36 -07001073SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001074 SkASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001075 SpvId result = this->nextId();
1076 std::vector<SpvId> arguments;
1077 for (size_t i = 0; i < c.fArguments.size(); i++) {
1078 arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1079 }
ethannicholasd598f792016-07-25 10:08:54 -07001080 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001081 if (c.fArguments.size() == 1) {
1082 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001083 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001084 this->writeWord(type, fConstantBuffer);
1085 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001086 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001087 this->writeWord(arguments[0], fConstantBuffer);
1088 }
1089 } else {
Greg Daniel64773e62016-11-22 09:44:03 -05001090 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001091 fConstantBuffer);
1092 this->writeWord(type, fConstantBuffer);
1093 this->writeWord(result, fConstantBuffer);
1094 for (SpvId id : arguments) {
1095 this->writeWord(id, fConstantBuffer);
1096 }
1097 }
1098 return result;
1099}
1100
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001101SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001102 SkASSERT(c.fType.isFloat());
1103 SkASSERT(c.fArguments.size() == 1);
1104 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001105 SpvId result = this->nextId();
1106 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001107 if (c.fArguments[0]->fType.isSigned()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001108 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001109 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001110 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001111 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Greg Daniel64773e62016-11-22 09:44:03 -05001112 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001113 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001114 }
1115 return result;
1116}
1117
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001118SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001119 SkASSERT(c.fType.isSigned());
1120 SkASSERT(c.fArguments.size() == 1);
1121 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001122 SpvId result = this->nextId();
1123 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001124 if (c.fArguments[0]->fType.isFloat()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001125 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001126 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001127 }
1128 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001129 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001130 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001131 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001132 }
1133 return result;
1134}
1135
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001136SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001137 SkASSERT(c.fType.isUnsigned());
1138 SkASSERT(c.fArguments.size() == 1);
1139 SkASSERT(c.fArguments[0]->fType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001140 SpvId result = this->nextId();
1141 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001142 if (c.fArguments[0]->fType.isFloat()) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001143 this->writeInstruction(SpvOpConvertFToU, this->getType(c.fType), result, parameter,
1144 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001145 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001146 SkASSERT(c.fArguments[0]->fType.isSigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001147 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
1148 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001149 }
1150 return result;
1151}
1152
Ethan Nicholas84645e32017-02-09 13:57:14 -05001153void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001154 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001155 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001156 SpvId zeroId = this->writeFloatLiteral(zero);
1157 std::vector<SpvId> columnIds;
1158 for (int column = 0; column < type.columns(); column++) {
1159 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1160 out);
1161 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1162 out);
1163 SpvId columnId = this->nextId();
1164 this->writeWord(columnId, out);
1165 columnIds.push_back(columnId);
1166 for (int row = 0; row < type.columns(); row++) {
1167 this->writeWord(row == column ? diagonal : zeroId, out);
1168 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001169 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001170 }
1171 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1172 out);
1173 this->writeWord(this->getType(type), out);
1174 this->writeWord(id, out);
1175 for (SpvId id : columnIds) {
1176 this->writeWord(id, out);
1177 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001178 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001179}
1180
1181void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001182 const Type& dstType, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001183 SkASSERT(srcType.kind() == Type::kMatrix_Kind);
1184 SkASSERT(dstType.kind() == Type::kMatrix_Kind);
1185 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001186 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1187 srcType.rows(),
1188 1));
1189 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1190 dstType.rows(),
1191 1));
1192 SpvId zeroId;
1193 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001194 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001195 zeroId = this->writeFloatLiteral(zero);
1196 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001197 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001198 zeroId = this->writeIntLiteral(zero);
1199 } else {
1200 ABORT("unsupported matrix component type");
1201 }
1202 SpvId zeroColumn = 0;
1203 SpvId columns[4];
1204 for (int i = 0; i < dstType.columns(); i++) {
1205 if (i < srcType.columns()) {
1206 // we're still inside the src matrix, copy the column
1207 SpvId srcColumn = this->nextId();
1208 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001209 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001210 SpvId dstColumn;
1211 if (srcType.rows() == dstType.rows()) {
1212 // columns are equal size, don't need to do anything
1213 dstColumn = srcColumn;
1214 }
1215 else if (dstType.rows() > srcType.rows()) {
1216 // dst column is bigger, need to zero-pad it
1217 dstColumn = this->nextId();
1218 int delta = dstType.rows() - srcType.rows();
1219 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1220 this->writeWord(dstColumnType, out);
1221 this->writeWord(dstColumn, out);
1222 this->writeWord(srcColumn, out);
1223 for (int i = 0; i < delta; ++i) {
1224 this->writeWord(zeroId, out);
1225 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001226 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001227 }
1228 else {
1229 // dst column is smaller, need to swizzle the src column
1230 dstColumn = this->nextId();
1231 int count = dstType.rows();
1232 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1233 this->writeWord(dstColumnType, out);
1234 this->writeWord(dstColumn, out);
1235 this->writeWord(srcColumn, out);
1236 this->writeWord(srcColumn, out);
1237 for (int i = 0; i < count; i++) {
1238 this->writeWord(i, out);
1239 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001240 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001241 }
1242 columns[i] = dstColumn;
1243 } else {
1244 // we're past the end of the src matrix, need a vector of zeroes
1245 if (!zeroColumn) {
1246 zeroColumn = this->nextId();
1247 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1248 this->writeWord(dstColumnType, out);
1249 this->writeWord(zeroColumn, out);
1250 for (int i = 0; i < dstType.rows(); ++i) {
1251 this->writeWord(zeroId, out);
1252 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001253 this->writePrecisionModifier(dstType, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001254 }
1255 columns[i] = zeroColumn;
1256 }
1257 }
1258 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1259 this->writeWord(this->getType(dstType), out);
1260 this->writeWord(id, out);
1261 for (int i = 0; i < dstType.columns(); i++) {
1262 this->writeWord(columns[i], out);
1263 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001264 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001265}
1266
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001267void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1268 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001269 std::vector<SpvId>* columnIds,
1270 int* currentCount, int rows, SpvId entry,
1271 OutputStream& out) {
1272 SkASSERT(*currentCount < rows);
1273 ++(*currentCount);
1274 currentColumn->push_back(entry);
1275 if (*currentCount == rows) {
1276 *currentCount = 0;
1277 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1278 this->writeWord(columnType, out);
1279 SpvId columnId = this->nextId();
1280 this->writeWord(columnId, out);
1281 columnIds->push_back(columnId);
1282 for (SpvId id : *currentColumn) {
1283 this->writeWord(id, out);
1284 }
1285 currentColumn->clear();
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001286 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001287 }
1288}
1289
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001290SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001291 SkASSERT(c.fType.kind() == Type::kMatrix_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001292 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1293 // an instruction
1294 std::vector<SpvId> arguments;
1295 for (size_t i = 0; i < c.fArguments.size(); i++) {
1296 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1297 }
1298 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001299 int rows = c.fType.rows();
1300 int columns = c.fType.columns();
Ethan Nicholas84645e32017-02-09 13:57:14 -05001301 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1302 this->writeUniformScaleMatrix(result, arguments[0], c.fType, out);
1303 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kMatrix_Kind) {
1304 this->writeMatrixCopy(result, arguments[0], c.fArguments[0]->fType, c.fType, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001305 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kVector_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001306 SkASSERT(c.fType.rows() == 2 && c.fType.columns() == 2);
1307 SkASSERT(c.fArguments[0]->fType.columns() == 4);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001308 SpvId componentType = this->getType(c.fType.componentType());
1309 SpvId v[4];
1310 for (int i = 0; i < 4; ++i) {
1311 v[i] = this->nextId();
1312 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i, out);
1313 }
1314 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, 2, 1));
1315 SpvId column1 = this->nextId();
1316 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1317 SpvId column2 = this->nextId();
1318 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
1319 this->writeInstruction(SpvOpCompositeConstruct, this->getType(c.fType), result, column1,
1320 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001321 } else {
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001322 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001323 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001324 // ids of vectors and scalars we have written to the current column so far
1325 std::vector<SpvId> currentColumn;
1326 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001327 int currentCount = 0;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001328 Precision precision = c.fType.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001329 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001330 if (currentCount == 0 && c.fArguments[i]->fType.kind() == Type::kVector_Kind &&
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001331 c.fArguments[i]->fType.columns() == c.fType.rows()) {
1332 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001333 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001334 } else {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001335 if (c.fArguments[i]->fType.columns() == 1) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001336 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1337 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001338 } else {
1339 SpvId componentType = this->getType(c.fArguments[i]->fType.componentType());
Ethan Nicholas811b9442018-05-11 13:16:03 -04001340 for (int j = 0; j < c.fArguments[i]->fType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001341 SpvId swizzle = this->nextId();
1342 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1343 arguments[i], j, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001344 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1345 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001346 }
1347 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001348 }
1349 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001350 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001351 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001352 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001353 this->writeWord(result, out);
1354 for (SpvId id : columnIds) {
1355 this->writeWord(id, out);
1356 }
1357 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001358 this->writePrecisionModifier(c.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001359 return result;
1360}
1361
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001362SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001363 SkASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001364 if (c.isConstant()) {
1365 return this->writeConstantVector(c);
1366 }
1367 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1368 // an instruction
1369 std::vector<SpvId> arguments;
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001370 for (size_t i = 0; i < c.fArguments.size(); i++) {
1371 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
1372 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1373 // extract the components and convert them in that case manually. On top of that,
1374 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1375 // doesn't handle vector arguments at all, so we always extract vector components and
1376 // pass them into OpCreateComposite individually.
1377 SpvId vec = this->writeExpression(*c.fArguments[i], out);
1378 SpvOp_ op = SpvOpUndef;
1379 const Type& src = c.fArguments[i]->fType.componentType();
1380 const Type& dst = c.fType.componentType();
1381 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1382 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1383 if (c.fArguments.size() == 1) {
1384 return vec;
1385 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001386 } else if (src == *fContext.fInt_Type ||
1387 src == *fContext.fShort_Type ||
1388 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001389 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001390 } else if (src == *fContext.fUInt_Type ||
1391 src == *fContext.fUShort_Type ||
1392 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001393 op = SpvOpConvertUToF;
1394 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001395 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001396 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001397 } else if (dst == *fContext.fInt_Type ||
1398 dst == *fContext.fShort_Type ||
1399 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001400 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1401 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001402 } else if (src == *fContext.fInt_Type ||
1403 src == *fContext.fShort_Type ||
1404 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001405 if (c.fArguments.size() == 1) {
1406 return vec;
1407 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001408 } else if (src == *fContext.fUInt_Type ||
1409 src == *fContext.fUShort_Type ||
1410 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001411 op = SpvOpBitcast;
1412 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001413 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001414 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001415 } else if (dst == *fContext.fUInt_Type ||
1416 dst == *fContext.fUShort_Type ||
1417 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001418 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1419 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001420 } else if (src == *fContext.fInt_Type ||
1421 src == *fContext.fShort_Type ||
1422 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001423 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001424 } else if (src == *fContext.fUInt_Type ||
1425 src == *fContext.fUShort_Type ||
1426 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001427 if (c.fArguments.size() == 1) {
1428 return vec;
1429 }
1430 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001431 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001432 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001433 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001434 for (int j = 0; j < c.fArguments[i]->fType.columns(); j++) {
1435 SpvId swizzle = this->nextId();
1436 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1437 out);
1438 if (op != SpvOpUndef) {
1439 SpvId cast = this->nextId();
1440 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1441 arguments.push_back(cast);
1442 } else {
1443 arguments.push_back(swizzle);
1444 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001445 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001446 } else {
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001447 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1448 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001449 }
1450 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001451 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1452 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1453 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001454 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001455 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001456 this->writeWord(arguments[0], out);
1457 }
1458 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001459 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001460 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001461 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001462 this->writeWord(result, out);
1463 for (SpvId id : arguments) {
1464 this->writeWord(id, out);
1465 }
1466 }
1467 return result;
1468}
1469
Ethan Nicholasbd553222017-07-18 15:54:59 -04001470SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001471 SkASSERT(c.fType.kind() == Type::kArray_Kind);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001472 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1473 // an instruction
1474 std::vector<SpvId> arguments;
1475 for (size_t i = 0; i < c.fArguments.size(); i++) {
1476 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1477 }
1478 SpvId result = this->nextId();
1479 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
1480 this->writeWord(this->getType(c.fType), out);
1481 this->writeWord(result, out);
1482 for (SpvId id : arguments) {
1483 this->writeWord(id, out);
1484 }
1485 return result;
1486}
1487
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001488SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001489 if (c.fArguments.size() == 1 &&
1490 this->getActualType(c.fType) == this->getActualType(c.fArguments[0]->fType)) {
1491 return this->writeExpression(*c.fArguments[0], out);
1492 }
1493 if (c.fType == *fContext.fFloat_Type || c.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001494 return this->writeFloatConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001495 } else if (c.fType == *fContext.fInt_Type ||
1496 c.fType == *fContext.fShort_Type ||
1497 c.fType == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001498 return this->writeIntConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001499 } else if (c.fType == *fContext.fUInt_Type ||
1500 c.fType == *fContext.fUShort_Type ||
1501 c.fType == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001502 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001503 }
ethannicholasd598f792016-07-25 10:08:54 -07001504 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001505 case Type::kVector_Kind:
1506 return this->writeVectorConstructor(c, out);
1507 case Type::kMatrix_Kind:
1508 return this->writeMatrixConstructor(c, out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001509 case Type::kArray_Kind:
1510 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001511 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001512#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07001513 ABORT("unsupported constructor: %s", c.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001514#endif
1515 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001516 }
1517}
1518
1519SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1520 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001521 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001522 return SpvStorageClassInput;
1523 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001524 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001525 return SpvStorageClassOutput;
1526 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001527 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001528 return SpvStorageClassPushConstant;
1529 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001530 return SpvStorageClassUniform;
1531 } else {
1532 return SpvStorageClassFunction;
1533 }
1534}
1535
ethannicholasf789b382016-08-03 12:43:36 -07001536SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001537 switch (expr.fKind) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001538 case Expression::kVariableReference_Kind: {
1539 const Variable& var = ((VariableReference&) expr).fVariable;
1540 if (var.fStorage != Variable::kGlobal_Storage) {
1541 return SpvStorageClassFunction;
1542 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001543 SpvStorageClass_ result = get_storage_class(var.fModifiers);
1544 if (result == SpvStorageClassFunction) {
1545 result = SpvStorageClassPrivate;
1546 }
1547 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001548 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001549 case Expression::kFieldAccess_Kind:
1550 return get_storage_class(*((FieldAccess&) expr).fBase);
1551 case Expression::kIndex_Kind:
1552 return get_storage_class(*((IndexExpression&) expr).fBase);
1553 default:
1554 return SpvStorageClassFunction;
1555 }
1556}
1557
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001558std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001559 std::vector<SpvId> chain;
1560 switch (expr.fKind) {
1561 case Expression::kIndex_Kind: {
1562 IndexExpression& indexExpr = (IndexExpression&) expr;
1563 chain = this->getAccessChain(*indexExpr.fBase, out);
1564 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1565 break;
1566 }
1567 case Expression::kFieldAccess_Kind: {
1568 FieldAccess& fieldExpr = (FieldAccess&) expr;
1569 chain = this->getAccessChain(*fieldExpr.fBase, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001570 IntLiteral index(fContext, -1, fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001571 chain.push_back(this->writeIntLiteral(index));
1572 break;
1573 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001574 default: {
1575 SpvId id = this->getLValue(expr, out)->getPointer();
1576 SkASSERT(id != 0);
1577 chain.push_back(id);
1578 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001579 }
1580 return chain;
1581}
1582
1583class PointerLValue : public SPIRVCodeGenerator::LValue {
1584public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001585 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1586 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001587 : fGen(gen)
1588 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001589 , fType(type)
1590 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001591
1592 virtual SpvId getPointer() override {
1593 return fPointer;
1594 }
1595
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001596 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001597 SpvId result = fGen.nextId();
1598 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001599 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001600 return result;
1601 }
1602
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001603 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001604 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1605 }
1606
1607private:
1608 SPIRVCodeGenerator& fGen;
1609 const SpvId fPointer;
1610 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001611 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001612};
1613
1614class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1615public:
Greg Daniel64773e62016-11-22 09:44:03 -05001616 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001617 const Type& baseType, const Type& swizzleType,
1618 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001619 : fGen(gen)
1620 , fVecPointer(vecPointer)
1621 , fComponents(components)
1622 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001623 , fSwizzleType(swizzleType)
1624 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001625
1626 virtual SpvId getPointer() override {
1627 return 0;
1628 }
1629
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001630 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001631 SpvId base = fGen.nextId();
1632 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001633 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001634 SpvId result = fGen.nextId();
1635 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1636 fGen.writeWord(fGen.getType(fSwizzleType), out);
1637 fGen.writeWord(result, out);
1638 fGen.writeWord(base, out);
1639 fGen.writeWord(base, out);
1640 for (int component : fComponents) {
1641 fGen.writeWord(component, out);
1642 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001643 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001644 return result;
1645 }
1646
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001647 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001648 // use OpVectorShuffle to mix and match the vector components. We effectively create
1649 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001650 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001651 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001652 // float3L = ...;
1653 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001654 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001655 // 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 -07001656 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1657 // (3, 1, 4).
1658 SpvId base = fGen.nextId();
1659 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1660 SpvId shuffle = fGen.nextId();
1661 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1662 fGen.writeWord(fGen.getType(fBaseType), out);
1663 fGen.writeWord(shuffle, out);
1664 fGen.writeWord(base, out);
1665 fGen.writeWord(value, out);
1666 for (int i = 0; i < fBaseType.columns(); i++) {
1667 // current offset into the virtual vector, defaults to pulling the unmodified
1668 // value from the left side
1669 int offset = i;
1670 // check to see if we are writing this component
1671 for (size_t j = 0; j < fComponents.size(); j++) {
1672 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001673 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001674 // the correct component of the right side instead of preserving the
1675 // value from the left
1676 offset = (int) (j + fBaseType.columns());
1677 break;
1678 }
1679 }
1680 fGen.writeWord(offset, out);
1681 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001682 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001683 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1684 }
1685
1686private:
1687 SPIRVCodeGenerator& fGen;
1688 const SpvId fVecPointer;
1689 const std::vector<int>& fComponents;
1690 const Type& fBaseType;
1691 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001692 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001693};
1694
Greg Daniel64773e62016-11-22 09:44:03 -05001695std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001696 OutputStream& out) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001697 Precision precision = expr.fType.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001698 switch (expr.fKind) {
1699 case Expression::kVariableReference_Kind: {
Ethan Nicholas5226b772018-05-03 16:20:41 -04001700 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07001701 const Variable& var = ((VariableReference&) expr).fVariable;
Ethan Nicholas5226b772018-05-03 16:20:41 -04001702 if (var.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
1703 type = this->getType(Type("sk_in", Type::kArray_Kind, var.fType.componentType(),
1704 fSkInCount));
1705 } else {
1706 type = this->getType(expr.fType);
1707 }
ethannicholasd598f792016-07-25 10:08:54 -07001708 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001709 SkASSERT(entry != fVariableMap.end());
Ethan Nicholas5226b772018-05-03 16:20:41 -04001710 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(*this,
1711 entry->second,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001712 type,
1713 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001714 }
1715 case Expression::kIndex_Kind: // fall through
1716 case Expression::kFieldAccess_Kind: {
1717 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1718 SpvId member = this->nextId();
1719 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001720 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001721 this->writeWord(member, out);
1722 for (SpvId idx : chain) {
1723 this->writeWord(idx, out);
1724 }
1725 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -04001726 *this,
1727 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001728 this->getType(expr.fType),
1729 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001730 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001731 case Expression::kSwizzle_Kind: {
1732 Swizzle& swizzle = (Swizzle&) expr;
1733 size_t count = swizzle.fComponents.size();
1734 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001735 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001736 if (count == 1) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001737 IntLiteral index(fContext, -1, swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001738 SpvId member = this->nextId();
1739 this->writeInstruction(SpvOpAccessChain,
Greg Daniel64773e62016-11-22 09:44:03 -05001740 this->getPointerType(swizzle.fType,
1741 get_storage_class(*swizzle.fBase)),
1742 member,
1743 base,
1744 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001745 out);
1746 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1747 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001748 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001749 this->getType(expr.fType),
1750 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001751 } else {
1752 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
Greg Daniel64773e62016-11-22 09:44:03 -05001753 *this,
1754 base,
1755 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001756 swizzle.fBase->fType,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001757 expr.fType,
1758 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001759 }
1760 }
Ethan Nicholasa583b812018-01-18 13:32:11 -05001761 case Expression::kTernary_Kind: {
1762 TernaryExpression& t = (TernaryExpression&) expr;
1763 SpvId test = this->writeExpression(*t.fTest, out);
1764 SpvId end = this->nextId();
1765 SpvId ifTrueLabel = this->nextId();
1766 SpvId ifFalseLabel = this->nextId();
1767 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1768 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1769 this->writeLabel(ifTrueLabel, out);
1770 SpvId ifTrue = this->getLValue(*t.fIfTrue, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001771 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001772 this->writeInstruction(SpvOpBranch, end, out);
1773 ifTrueLabel = fCurrentBlock;
1774 SpvId ifFalse = this->getLValue(*t.fIfFalse, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001775 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001776 ifFalseLabel = fCurrentBlock;
1777 this->writeInstruction(SpvOpBranch, end, out);
1778 SpvId result = this->nextId();
1779 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1780 ifTrueLabel, ifFalse, ifFalseLabel, out);
1781 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1782 *this,
1783 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001784 this->getType(expr.fType),
1785 precision));
Ethan Nicholasa583b812018-01-18 13:32:11 -05001786 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001787 default:
1788 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001789 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001790 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1791 // caught by IRGenerator
1792 SpvId result = this->nextId();
1793 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001794 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1795 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001796 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1797 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1798 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001799 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001800 this->getType(expr.fType),
1801 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001802 }
1803}
1804
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001805SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001806 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001807 auto entry = fVariableMap.find(&ref.fVariable);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001808 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001809 SpvId var = entry->second;
ethannicholasd598f792016-07-25 10:08:54 -07001810 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001811 this->writePrecisionModifier(ref.fVariable.fType, result);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001812 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
Greg Daniela85e4bf2020-06-17 16:32:45 -04001813 (fProgram.fSettings.fFlipY || fProgram.fSettings.fInverseW)) {
1814 // The x component never changes, so just grab it
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001815 SpvId xId = this->nextId();
1816 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1817 result, 0, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001818
1819 // Calculate the y component which may need to be flipped
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001820 SpvId rawYId = this->nextId();
1821 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1822 result, 1, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001823 SpvId flippedYId = 0;
1824 if (fProgram.fSettings.fFlipY) {
1825 // need to remap to a top-left coordinate system
1826 if (fRTHeightStructId == (SpvId)-1) {
1827 // height variable hasn't been written yet
1828 std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors));
1829 SkASSERT(fRTHeightFieldIndex == (SpvId)-1);
1830 std::vector<Type::Field> fields;
1831 SkASSERT(fProgram.fSettings.fRTHeightOffset >= 0);
1832 fields.emplace_back(
1833 Modifiers(Layout(0, -1, fProgram.fSettings.fRTHeightOffset, -1, -1, -1, -1,
1834 -1, Layout::Format::kUnspecified,
1835 Layout::kUnspecified_Primitive, 1, -1, "", "",
1836 Layout::kNo_Key, Layout::CType::kDefault),
1837 0),
1838 SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1839 StringFragment name("sksl_synthetic_uniforms");
1840 Type intfStruct(-1, name, fields);
1841
1842 int binding = fProgram.fSettings.fRTHeightBinding;
1843 int set = fProgram.fSettings.fRTHeightSet;
1844 SkASSERT(binding != -1 && set != -1);
1845
1846 Layout layout(0, -1, -1, binding, -1, set, -1, -1, Layout::Format::kUnspecified,
1847 Layout::kUnspecified_Primitive, -1, -1, "", "", Layout::kNo_Key,
1848 Layout::CType::kDefault);
1849 Variable* intfVar = (Variable*)fSynthetics.takeOwnership(std::unique_ptr<Symbol>(
1850 new Variable(-1,
1851 Modifiers(layout, Modifiers::kUniform_Flag),
1852 name,
1853 intfStruct,
1854 Variable::kGlobal_Storage)));
1855 InterfaceBlock intf(-1, intfVar, name, String(""),
1856 std::vector<std::unique_ptr<Expression>>(), st);
Stephen White88574972020-06-23 19:09:29 -04001857
1858 fRTHeightStructId = this->writeInterfaceBlock(intf, false);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001859 fRTHeightFieldIndex = 0;
1860 }
1861 SkASSERT(fRTHeightFieldIndex != (SpvId)-1);
1862
1863 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1864 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1865 SpvId heightPtr = this->nextId();
1866 this->writeOpCode(SpvOpAccessChain, 5, out);
1867 this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform),
1868 out);
1869 this->writeWord(heightPtr, out);
1870 this->writeWord(fRTHeightStructId, out);
1871 this->writeWord(fieldIndexId, out);
1872 SpvId heightRead = this->nextId();
1873 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1874 heightPtr, out);
1875
1876 flippedYId = this->nextId();
1877 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
1878 heightRead, rawYId, out);
1879 }
1880
1881 // The z component will always be zero so we just get an id to the 0 literal
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001882 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001883 SpvId zeroId = writeFloatLiteral(zero);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001884
1885 // Calculate the w component which may need to be inverted
1886 SpvId rawWId = this->nextId();
1887 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawWId,
Ethan Nicholas20798e52018-12-04 12:30:50 -05001888 result, 3, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001889 SpvId invWId = 0;
1890 if (fProgram.fSettings.fInverseW) {
1891 // We need to invert w
1892 FloatLiteral one(fContext, -1, 1.0);
1893 SpvId oneId = writeFloatLiteral(one);
1894 invWId = this->nextId();
1895 this->writeInstruction(SpvOpFDiv, this->getType(*fContext.fFloat_Type), invWId, oneId,
1896 rawWId, out);
1897 }
1898
1899 // Fill in the new fragcoord with the components from above
1900 SpvId adjusted = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001901 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001902 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001903 this->writeWord(adjusted, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001904 this->writeWord(xId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001905 if (fProgram.fSettings.fFlipY) {
1906 this->writeWord(flippedYId, out);
1907 } else {
1908 this->writeWord(rawYId, out);
1909 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001910 this->writeWord(zeroId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001911 if (fProgram.fSettings.fInverseW) {
1912 this->writeWord(invWId, out);
1913 } else {
1914 this->writeWord(rawWId, out);
1915 }
1916
1917 return adjusted;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001918 }
Chris Daltonb91c4662018-08-01 10:46:22 -06001919 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
1920 !fProgram.fSettings.fFlipY) {
1921 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1922 // the default convention of "counter-clockwise face is front".
1923 SpvId inverse = this->nextId();
1924 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1925 result, out);
1926 return inverse;
1927 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001928 return result;
1929}
1930
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001931SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001932 if (expr.fBase->fType.kind() == Type::Kind::kVector_Kind) {
1933 SpvId base = this->writeExpression(*expr.fBase, out);
1934 SpvId index = this->writeExpression(*expr.fIndex, out);
1935 SpvId result = this->nextId();
1936 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.fType), result, base,
1937 index, out);
1938 return result;
1939 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001940 return getLValue(expr, out)->load(out);
1941}
1942
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001943SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001944 return getLValue(f, out)->load(out);
1945}
1946
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001947SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001948 SpvId base = this->writeExpression(*swizzle.fBase, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001949 SpvId result = this->nextId();
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001950 size_t count = swizzle.fComponents.size();
ethannicholasb3058bd2016-07-01 08:22:01 -07001951 if (count == 1) {
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001952 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
1953 swizzle.fComponents[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001954 } else {
1955 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001956 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001957 this->writeWord(result, out);
1958 this->writeWord(base, out);
Ethan Nicholase455f652019-09-13 12:52:55 -04001959 SpvId other = base;
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001960 for (int c : swizzle.fComponents) {
Ethan Nicholase455f652019-09-13 12:52:55 -04001961 if (c < 0) {
1962 if (!fConstantZeroOneVector) {
1963 FloatLiteral zero(fContext, -1, 0);
1964 SpvId zeroId = this->writeFloatLiteral(zero);
1965 FloatLiteral one(fContext, -1, 1);
1966 SpvId oneId = this->writeFloatLiteral(one);
1967 SpvId type = this->getType(*fContext.fFloat2_Type);
1968 fConstantZeroOneVector = this->nextId();
1969 this->writeOpCode(SpvOpConstantComposite, 5, fConstantBuffer);
1970 this->writeWord(type, fConstantBuffer);
1971 this->writeWord(fConstantZeroOneVector, fConstantBuffer);
1972 this->writeWord(zeroId, fConstantBuffer);
1973 this->writeWord(oneId, fConstantBuffer);
1974 }
1975 other = fConstantZeroOneVector;
1976 break;
Ethan Nicholasac285b12019-02-12 16:05:18 -05001977 }
Ethan Nicholasac285b12019-02-12 16:05:18 -05001978 }
1979 this->writeWord(other, out);
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001980 for (int component : swizzle.fComponents) {
Ethan Nicholasac285b12019-02-12 16:05:18 -05001981 if (component == SKSL_SWIZZLE_0) {
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001982 this->writeWord(swizzle.fBase->fType.columns(), out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001983 } else if (component == SKSL_SWIZZLE_1) {
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001984 this->writeWord(swizzle.fBase->fType.columns() + 1, out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001985 } else {
1986 this->writeWord(component, out);
1987 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001988 }
1989 }
1990 return result;
1991}
1992
Greg Daniel64773e62016-11-22 09:44:03 -05001993SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1994 const Type& operandType, SpvId lhs,
1995 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001996 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001997 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001998 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001999 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002000 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002001 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002002 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002003 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002004 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002005 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002006 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07002007 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002008#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002009 ABORT("invalid operandType: %s", operandType.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002010#endif
ethannicholasb3058bd2016-07-01 08:22:01 -07002011 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04002012 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002013 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
2014 fDecorationBuffer);
2015 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002016 return result;
2017}
2018
Ethan Nicholas48e24052018-03-14 13:51:39 -04002019SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
2020 OutputStream& out) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002021 if (operandType.kind() == Type::kVector_Kind) {
2022 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04002023 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002024 return result;
2025 }
2026 return id;
2027}
2028
Ethan Nicholas68990be2017-07-13 09:36:52 -04002029SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
2030 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002031 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04002032 OutputStream& out) {
2033 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002034 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002035 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2036 operandType.rows(),
2037 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04002038 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002039 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04002040 1));
2041 SpvId boolType = this->getType(*fContext.fBool_Type);
2042 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04002043 for (int i = 0; i < operandType.columns(); i++) {
2044 SpvId columnL = this->nextId();
2045 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2046 SpvId columnR = this->nextId();
2047 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002048 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002049 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
2050 SpvId merge = this->nextId();
2051 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002052 if (result != 0) {
2053 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002054 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002055 result = next;
2056 }
2057 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002058 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04002059 }
2060 }
2061 return result;
2062}
2063
Ethan Nicholas0df21132018-07-10 09:37:51 -04002064SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
2065 SpvId rhs, SpvOp_ floatOperator,
2066 SpvOp_ intOperator,
2067 OutputStream& out) {
2068 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
2069 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
2070 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2071 operandType.rows(),
2072 1));
2073 SpvId columns[4];
2074 for (int i = 0; i < operandType.columns(); i++) {
2075 SpvId columnL = this->nextId();
2076 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2077 SpvId columnR = this->nextId();
2078 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2079 columns[i] = this->nextId();
2080 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2081 }
2082 SpvId result = this->nextId();
2083 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2084 this->writeWord(this->getType(operandType), out);
2085 this->writeWord(result, out);
2086 for (int i = 0; i < operandType.columns(); i++) {
2087 this->writeWord(columns[i], out);
2088 }
2089 return result;
2090}
2091
Ethan Nicholas49465b42019-04-17 12:22:21 -04002092std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2093 if (type.isInteger()) {
2094 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002095 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002096 else if (type.isFloat()) {
2097 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002098 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002099 ABORT("math is unsupported on type '%s'", type.name().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002100 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002101}
2102
2103SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Token::Kind op,
2104 const Type& rightType, SpvId rhs,
2105 const Type& resultType, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002106 Type tmp("<invalid>");
Ethan Nicholas48e24052018-03-14 13:51:39 -04002107 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002108 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002109 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2110 // handling in SPIR-V
Ethan Nicholas49465b42019-04-17 12:22:21 -04002111 if (this->getActualType(leftType) != this->getActualType(rightType)) {
2112 if (leftType.kind() == Type::kVector_Kind && rightType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002113 if (op == Token::Kind::TK_SLASH) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002114 SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
2115 SpvId inverse = this->nextId();
2116 this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
2117 rhs = inverse;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002118 op = Token::Kind::TK_STAR;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002119 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002120 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002121 SpvId result = this->nextId();
2122 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2123 result, lhs, rhs, out);
2124 return result;
2125 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002126 // promote number to vector
2127 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002128 const Type& vecType = leftType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002129 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2130 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002131 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002132 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002133 this->writeWord(rhs, out);
2134 }
2135 rhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002136 operandType = &leftType;
2137 } else if (rightType.kind() == Type::kVector_Kind && leftType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002138 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002139 SpvId result = this->nextId();
2140 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2141 result, rhs, lhs, out);
2142 return result;
2143 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002144 // promote number to vector
2145 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002146 const Type& vecType = rightType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002147 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2148 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002149 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002150 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002151 this->writeWord(lhs, out);
2152 }
2153 lhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002154 operandType = &rightType;
2155 } else if (leftType.kind() == Type::kMatrix_Kind) {
2156 SpvOp_ spvop;
2157 if (rightType.kind() == Type::kMatrix_Kind) {
2158 spvop = SpvOpMatrixTimesMatrix;
2159 } else if (rightType.kind() == Type::kVector_Kind) {
2160 spvop = SpvOpMatrixTimesVector;
ethannicholasb3058bd2016-07-01 08:22:01 -07002161 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002162 SkASSERT(rightType.kind() == Type::kScalar_Kind);
2163 spvop = SpvOpMatrixTimesScalar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002164 }
2165 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002166 this->writeInstruction(spvop, this->getType(resultType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002167 return result;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002168 } else if (rightType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002169 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002170 if (leftType.kind() == Type::kVector_Kind) {
2171 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(resultType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002172 lhs, rhs, out);
2173 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002174 SkASSERT(leftType.kind() == Type::kScalar_Kind);
2175 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(resultType), result,
2176 rhs, lhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002177 }
2178 return result;
2179 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002180 SkASSERT(false);
2181 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002182 }
2183 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002184 tmp = this->getActualType(leftType);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002185 operandType = &tmp;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002186 SkASSERT(*operandType == this->getActualType(rightType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002187 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002188 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002189 case Token::Kind::TK_EQEQ: {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002190 if (operandType->kind() == Type::kMatrix_Kind) {
2191 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002192 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002193 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002194 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002195 const Type* tmpType;
2196 if (operandType->kind() == Type::kVector_Kind) {
2197 tmpType = &fContext.fBool_Type->toCompound(fContext,
2198 operandType->columns(),
2199 operandType->rows());
2200 } else {
2201 tmpType = &resultType;
2202 }
2203 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002204 SpvOpFOrdEqual, SpvOpIEqual,
2205 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002206 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002207 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002208 case Token::Kind::TK_NEQ:
Ethan Nicholas68990be2017-07-13 09:36:52 -04002209 if (operandType->kind() == Type::kMatrix_Kind) {
2210 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002211 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002212 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002213 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002214 const Type* tmpType;
2215 if (operandType->kind() == Type::kVector_Kind) {
2216 tmpType = &fContext.fBool_Type->toCompound(fContext,
2217 operandType->columns(),
2218 operandType->rows());
2219 } else {
2220 tmpType = &resultType;
2221 }
2222 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002223 SpvOpFOrdNotEqual, SpvOpINotEqual,
2224 SpvOpINotEqual, SpvOpLogicalNotEqual,
2225 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002226 *operandType, SpvOpAny, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002227 case Token::Kind::TK_GT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002228 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002229 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2230 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002231 SpvOpUGreaterThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002232 case Token::Kind::TK_LT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002233 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002234 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002235 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002236 case Token::Kind::TK_GTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002237 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002238 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2239 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002240 SpvOpUGreaterThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002241 case Token::Kind::TK_LTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002242 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002243 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2244 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002245 SpvOpULessThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002246 case Token::Kind::TK_PLUS:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002247 if (leftType.kind() == Type::kMatrix_Kind &&
2248 rightType.kind() == Type::kMatrix_Kind) {
2249 SkASSERT(leftType == rightType);
2250 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002251 SpvOpFAdd, SpvOpIAdd, out);
2252 }
Greg Daniel64773e62016-11-22 09:44:03 -05002253 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002254 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002255 case Token::Kind::TK_MINUS:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002256 if (leftType.kind() == Type::kMatrix_Kind &&
2257 rightType.kind() == Type::kMatrix_Kind) {
2258 SkASSERT(leftType == rightType);
2259 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002260 SpvOpFSub, SpvOpISub, out);
2261 }
Greg Daniel64773e62016-11-22 09:44:03 -05002262 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002263 SpvOpISub, SpvOpISub, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002264 case Token::Kind::TK_STAR:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002265 if (leftType.kind() == Type::kMatrix_Kind &&
2266 rightType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002267 // matrix multiply
2268 SpvId result = this->nextId();
2269 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2270 lhs, rhs, out);
2271 return result;
2272 }
Greg Daniel64773e62016-11-22 09:44:03 -05002273 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002274 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002275 case Token::Kind::TK_SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002276 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002277 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002278 case Token::Kind::TK_PERCENT:
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002279 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2280 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002281 case Token::Kind::TK_SHL:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002282 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2283 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2284 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002285 case Token::Kind::TK_SHR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002286 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2287 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2288 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002289 case Token::Kind::TK_BITWISEAND:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002290 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2291 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002292 case Token::Kind::TK_BITWISEOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002293 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2294 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002295 case Token::Kind::TK_BITWISEXOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002296 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2297 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002298 case Token::Kind::TK_COMMA:
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04002299 return rhs;
ethannicholasb3058bd2016-07-01 08:22:01 -07002300 default:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002301 SkASSERT(false);
2302 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002303 }
2304}
2305
Ethan Nicholas49465b42019-04-17 12:22:21 -04002306SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
2307 // handle cases where we don't necessarily evaluate both LHS and RHS
2308 switch (b.fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002309 case Token::Kind::TK_EQ: {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002310 SpvId rhs = this->writeExpression(*b.fRight, out);
2311 this->getLValue(*b.fLeft, out)->store(rhs, out);
2312 return rhs;
2313 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002314 case Token::Kind::TK_LOGICALAND:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002315 return this->writeLogicalAnd(b, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002316 case Token::Kind::TK_LOGICALOR:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002317 return this->writeLogicalOr(b, out);
2318 default:
2319 break;
2320 }
2321
2322 std::unique_ptr<LValue> lvalue;
2323 SpvId lhs;
2324 if (is_assignment(b.fOperator)) {
2325 lvalue = this->getLValue(*b.fLeft, out);
2326 lhs = lvalue->load(out);
2327 } else {
2328 lvalue = nullptr;
2329 lhs = this->writeExpression(*b.fLeft, out);
2330 }
2331 SpvId rhs = this->writeExpression(*b.fRight, out);
2332 SpvId result = this->writeBinaryExpression(b.fLeft->fType, lhs, remove_assignment(b.fOperator),
2333 b.fRight->fType, rhs, b.fType, out);
2334 if (lvalue) {
2335 lvalue->store(result, out);
2336 }
2337 return result;
2338}
2339
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002340SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002341 SkASSERT(a.fOperator == Token::Kind::TK_LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002342 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002343 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2344 SpvId lhs = this->writeExpression(*a.fLeft, out);
2345 SpvId rhsLabel = this->nextId();
2346 SpvId end = this->nextId();
2347 SpvId lhsBlock = fCurrentBlock;
2348 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2349 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2350 this->writeLabel(rhsLabel, out);
2351 SpvId rhs = this->writeExpression(*a.fRight, out);
2352 SpvId rhsBlock = fCurrentBlock;
2353 this->writeInstruction(SpvOpBranch, end, out);
2354 this->writeLabel(end, out);
2355 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002356 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002357 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002358 return result;
2359}
2360
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002361SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002362 SkASSERT(o.fOperator == Token::Kind::TK_LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002363 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002364 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2365 SpvId lhs = this->writeExpression(*o.fLeft, out);
2366 SpvId rhsLabel = this->nextId();
2367 SpvId end = this->nextId();
2368 SpvId lhsBlock = fCurrentBlock;
2369 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2370 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2371 this->writeLabel(rhsLabel, out);
2372 SpvId rhs = this->writeExpression(*o.fRight, out);
2373 SpvId rhsBlock = fCurrentBlock;
2374 this->writeInstruction(SpvOpBranch, end, out);
2375 this->writeLabel(end, out);
2376 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002377 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002378 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002379 return result;
2380}
2381
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002382SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002383 SpvId test = this->writeExpression(*t.fTest, out);
Ethan Nicholas0f21c232018-07-23 09:25:40 -04002384 if (t.fIfTrue->fType.columns() == 1 && t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002385 // both true and false are constants, can just use OpSelect
2386 SpvId result = this->nextId();
2387 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2388 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
Greg Daniel64773e62016-11-22 09:44:03 -05002389 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002390 out);
2391 return result;
2392 }
Greg Daniel64773e62016-11-22 09:44:03 -05002393 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002394 // Adreno. Switched to storing the result in a temp variable as glslang does.
2395 SpvId var = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002396 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002397 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002398 SpvId trueLabel = this->nextId();
2399 SpvId falseLabel = this->nextId();
2400 SpvId end = this->nextId();
2401 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2402 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2403 this->writeLabel(trueLabel, out);
2404 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2405 this->writeInstruction(SpvOpBranch, end, out);
2406 this->writeLabel(falseLabel, out);
2407 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2408 this->writeInstruction(SpvOpBranch, end, out);
2409 this->writeLabel(end, out);
2410 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002411 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002412 this->writePrecisionModifier(t.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002413 return result;
2414}
2415
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002416SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002417 if (p.fOperator == Token::Kind::TK_MINUS) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002418 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002419 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002420 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002421 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002422 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002423 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002424 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2425 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002426#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002427 ABORT("unsupported prefix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002428#endif
Brian Salomon23356442018-11-30 15:33:19 -05002429 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002430 this->writePrecisionModifier(p.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002431 return result;
2432 }
2433 switch (p.fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002434 case Token::Kind::TK_PLUS:
ethannicholasb3058bd2016-07-01 08:22:01 -07002435 return this->writeExpression(*p.fOperand, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002436 case Token::Kind::TK_PLUSPLUS: {
ethannicholasb3058bd2016-07-01 08:22:01 -07002437 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002438 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002439 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2440 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002441 out);
2442 lv->store(result, out);
2443 return result;
2444 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002445 case Token::Kind::TK_MINUSMINUS: {
ethannicholasb3058bd2016-07-01 08:22:01 -07002446 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002447 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002448 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2449 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002450 out);
2451 lv->store(result, out);
2452 return result;
2453 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002454 case Token::Kind::TK_LOGICALNOT: {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002455 SkASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002456 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002457 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002458 this->writeExpression(*p.fOperand, out), out);
2459 return result;
2460 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002461 case Token::Kind::TK_BITWISENOT: {
ethannicholas5961bc92016-10-12 06:39:56 -07002462 SpvId result = this->nextId();
2463 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2464 this->writeExpression(*p.fOperand, out), out);
2465 return result;
2466 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002467 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002468#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002469 ABORT("unsupported prefix expression: %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002470#endif
2471 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002472 }
2473}
2474
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002475SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002476 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2477 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002478 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002479 switch (p.fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002480 case Token::Kind::TK_PLUSPLUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002481 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002482 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2483 lv->store(temp, out);
2484 return result;
2485 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002486 case Token::Kind::TK_MINUSMINUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002487 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002488 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2489 lv->store(temp, out);
2490 return result;
2491 }
2492 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002493#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002494 ABORT("unsupported postfix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002495#endif
2496 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002497 }
2498}
2499
ethannicholasf789b382016-08-03 12:43:36 -07002500SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002501 if (b.fValue) {
2502 if (fBoolTrue == 0) {
2503 fBoolTrue = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002504 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002505 fConstantBuffer);
2506 }
2507 return fBoolTrue;
2508 } else {
2509 if (fBoolFalse == 0) {
2510 fBoolFalse = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002511 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002512 fConstantBuffer);
2513 }
2514 return fBoolFalse;
2515 }
2516}
2517
ethannicholasf789b382016-08-03 12:43:36 -07002518SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002519 ConstantType type;
ethannicholasd598f792016-07-25 10:08:54 -07002520 if (i.fType == *fContext.fInt_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002521 type = ConstantType::kInt;
2522 } else if (i.fType == *fContext.fUInt_Type) {
2523 type = ConstantType::kUInt;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002524 } else if (i.fType == *fContext.fShort_Type || i.fType == *fContext.fByte_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002525 type = ConstantType::kShort;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002526 } else if (i.fType == *fContext.fUShort_Type || i.fType == *fContext.fUByte_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002527 type = ConstantType::kUShort;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002528 } else {
2529 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002530 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002531 std::pair<ConstantValue, ConstantType> key(i.fValue, type);
2532 auto entry = fNumberConstants.find(key);
2533 if (entry == fNumberConstants.end()) {
2534 SpvId result = this->nextId();
2535 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
2536 fConstantBuffer);
2537 fNumberConstants[key] = result;
2538 return result;
2539 }
2540 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002541}
2542
ethannicholasf789b382016-08-03 12:43:36 -07002543SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
John Stiles8c578662020-06-01 15:32:47 +00002544 ConstantType type;
2545 if (f.fType == *fContext.fHalf_Type) {
2546 type = ConstantType::kHalf;
ethannicholasb3058bd2016-07-01 08:22:01 -07002547 } else {
John Stiles8c578662020-06-01 15:32:47 +00002548 type = ConstantType::kFloat;
ethannicholasb3058bd2016-07-01 08:22:01 -07002549 }
John Stiles8c578662020-06-01 15:32:47 +00002550 float value = (float) f.fValue;
2551 std::pair<ConstantValue, ConstantType> key(f.fValue, type);
2552 auto entry = fNumberConstants.find(key);
2553 if (entry == fNumberConstants.end()) {
2554 SpvId result = this->nextId();
2555 uint32_t bits;
2556 SkASSERT(sizeof(bits) == sizeof(value));
2557 memcpy(&bits, &value, sizeof(bits));
2558 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
2559 fConstantBuffer);
2560 fNumberConstants[key] = result;
2561 return result;
2562 }
2563 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002564}
2565
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002566SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002567 SpvId result = fFunctionMap[&f];
Greg Daniel64773e62016-11-22 09:44:03 -05002568 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002569 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002570 this->writeInstruction(SpvOpName, result, f.fName, fNameBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002571 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002572 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002573 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002574 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002575 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002576 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2577 }
2578 return result;
2579}
2580
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002581SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2582 fVariableBuffer.reset();
ethannicholasb3058bd2016-07-01 08:22:01 -07002583 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2584 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002585 StringStream bodyBuffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04002586 this->writeBlock((Block&) *f.fBody, bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002587 write_stringstream(fVariableBuffer, out);
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002588 if (f.fDeclaration.fName == "main") {
2589 write_stringstream(fGlobalInitializersBuffer, out);
2590 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002591 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002592 if (fCurrentBlock) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002593 if (f.fDeclaration.fReturnType == *fContext.fVoid_Type) {
2594 this->writeInstruction(SpvOpReturn, out);
2595 } else {
2596 this->writeInstruction(SpvOpUnreachable, out);
2597 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002598 }
2599 this->writeInstruction(SpvOpFunctionEnd, out);
2600 return result;
2601}
2602
2603void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2604 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002605 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002606 fDecorationBuffer);
2607 }
2608 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002609 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002610 fDecorationBuffer);
2611 }
2612 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002613 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002614 fDecorationBuffer);
2615 }
2616 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002617 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002618 fDecorationBuffer);
2619 }
Greg Daniel64773e62016-11-22 09:44:03 -05002620 if (layout.fInputAttachmentIndex >= 0) {
2621 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2622 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002623 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002624 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002625 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002626 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002627 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002628 fDecorationBuffer);
2629 }
2630}
2631
2632void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2633 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002634 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002635 layout.fLocation, fDecorationBuffer);
2636 }
2637 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002638 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002639 layout.fBinding, fDecorationBuffer);
2640 }
2641 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002642 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002643 layout.fIndex, fDecorationBuffer);
2644 }
2645 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002646 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002647 layout.fSet, fDecorationBuffer);
2648 }
Greg Daniel64773e62016-11-22 09:44:03 -05002649 if (layout.fInputAttachmentIndex >= 0) {
2650 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2651 layout.fInputAttachmentIndex, fDecorationBuffer);
2652 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002653 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002654 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002655 layout.fBuiltin, fDecorationBuffer);
2656 }
2657}
2658
Ethan Nicholas81d15112018-07-13 12:48:50 -04002659static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2660 switch (m.fLayout.fPrimitive) {
2661 case Layout::kPoints_Primitive:
2662 *outSkInCount = 1;
2663 break;
2664 case Layout::kLines_Primitive:
2665 *outSkInCount = 2;
2666 break;
2667 case Layout::kLinesAdjacency_Primitive:
2668 *outSkInCount = 4;
2669 break;
2670 case Layout::kTriangles_Primitive:
2671 *outSkInCount = 3;
2672 break;
2673 case Layout::kTrianglesAdjacency_Primitive:
2674 *outSkInCount = 6;
2675 break;
2676 default:
2677 return;
2678 }
2679}
2680
Stephen White88574972020-06-23 19:09:29 -04002681SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf, bool appendRTHeight) {
Ethan Nicholas361941e2017-05-30 15:41:07 -04002682 bool isBuffer = (0 != (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag));
Ethan Nicholas39204fd2017-11-27 13:12:30 -05002683 bool pushConstant = (0 != (intf.fVariable.fModifiers.fLayout.fFlags &
2684 Layout::kPushConstant_Flag));
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002685 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2686 MemoryLayout(MemoryLayout::k430_Standard) :
2687 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002688 SpvId result = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002689 const Type* type = &intf.fVariable.fType;
Stephen White88574972020-06-23 19:09:29 -04002690 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Greg Daniele6ab9982018-08-22 13:56:32 +00002691 SkASSERT(fRTHeightStructId == (SpvId) -1);
2692 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002693 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002694 fRTHeightStructId = result;
2695 fRTHeightFieldIndex = fields.size();
2696 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002697 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002698 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002699 SpvId typeId;
2700 if (intf.fVariable.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2701 for (const auto& e : fProgram) {
2702 if (e.fKind == ProgramElement::kModifiers_Kind) {
2703 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholas81d15112018-07-13 12:48:50 -04002704 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002705 }
2706 }
2707 typeId = this->getType(Type("sk_in", Type::kArray_Kind, intf.fVariable.fType.componentType(),
2708 fSkInCount), memoryLayout);
2709 } else {
2710 typeId = this->getType(*type, memoryLayout);
2711 }
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002712 if (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag) {
2713 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002714 } else if (intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
2715 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002716 }
ethannicholasd598f792016-07-25 10:08:54 -07002717 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002718 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002719 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002720 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002721 Layout layout = intf.fVariable.fModifiers.fLayout;
2722 if (intf.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
2723 layout.fSet = 0;
2724 }
2725 this->writeLayout(layout, result);
ethannicholasd598f792016-07-25 10:08:54 -07002726 fVariableMap[&intf.fVariable] = result;
Stephen White88574972020-06-23 19:09:29 -04002727 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002728 delete type;
2729 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002730 return result;
2731}
2732
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002733void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002734 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2735}
2736
2737void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2738 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002739 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2740 }
2741}
2742
Chris Dalton2284aab2019-11-15 11:02:24 -07002743bool is_dead(const Variable& var) {
2744 if (var.fReadCount || var.fWriteCount) {
2745 return false;
2746 }
2747 // not entirely sure what the rules are for when it's safe to elide interface variables, but it
2748 // causes various problems to elide some of them even when dead. But it also causes problems
2749 // *not* to elide sk_SampleMask when it's not being used.
2750 if (!(var.fModifiers.fFlags & (Modifiers::kIn_Flag |
2751 Modifiers::kOut_Flag |
2752 Modifiers::kUniform_Flag |
2753 Modifiers::kBuffer_Flag))) {
2754 return true;
2755 }
2756 return var.fModifiers.fLayout.fBuiltin == SK_SAMPLEMASK_BUILTIN;
2757}
2758
ethannicholas5961bc92016-10-12 06:39:56 -07002759#define BUILTIN_IGNORE 9999
Greg Daniel64773e62016-11-22 09:44:03 -05002760void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002761 OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002762 for (size_t i = 0; i < decl.fVars.size(); i++) {
2763 if (decl.fVars[i]->fKind == Statement::kNop_Kind) {
2764 continue;
2765 }
2766 const VarDeclaration& varDecl = (VarDeclaration&) *decl.fVars[i];
2767 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002768 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2769 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002770 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Chris Daltonb0fd4b12019-10-29 13:41:22 -06002771 Modifiers::kWriteOnly_Flag |
2772 Modifiers::kCoherent_Flag |
2773 Modifiers::kVolatile_Flag |
2774 Modifiers::kRestrict_Flag)));
ethannicholas5961bc92016-10-12 06:39:56 -07002775 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2776 continue;
2777 }
2778 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2779 kind != Program::kFragment_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002780 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
ethannicholas5961bc92016-10-12 06:39:56 -07002781 continue;
2782 }
Chris Dalton2284aab2019-11-15 11:02:24 -07002783 if (is_dead(*var)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002784 continue;
2785 }
2786 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002787 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002788 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002789 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002790 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002791 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
Stephen Whiteff5d7a22019-07-26 17:42:06 -04002792 if (var->fType.kind() == Type::kSampler_Kind ||
2793 var->fType.kind() == Type::kSeparateSampler_Kind ||
2794 var->fType.kind() == Type::kTexture_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002795 storageClass = SpvStorageClassUniformConstant;
2796 } else {
2797 storageClass = SpvStorageClassUniform;
2798 }
2799 } else {
2800 storageClass = SpvStorageClassPrivate;
2801 }
2802 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002803 fVariableMap[var] = id;
Ethan Nicholas5226b772018-05-03 16:20:41 -04002804 SpvId type;
2805 if (var->fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2806 type = this->getPointerType(Type("sk_in", Type::kArray_Kind,
2807 var->fType.componentType(), fSkInCount),
2808 storageClass);
2809 } else {
2810 type = this->getPointerType(var->fType, storageClass);
2811 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002812 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002813 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002814 this->writePrecisionModifier(var->fType, id);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002815 if (varDecl.fValue) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002816 SkASSERT(!fCurrentBlock);
ethannicholasf789b382016-08-03 12:43:36 -07002817 fCurrentBlock = -1;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002818 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002819 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002820 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002821 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002822 this->writeLayout(var->fModifiers.fLayout, id);
Ethan Nicholas45b0f152017-07-24 14:36:40 -04002823 if (var->fModifiers.fFlags & Modifiers::kFlat_Flag) {
2824 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2825 }
2826 if (var->fModifiers.fFlags & Modifiers::kNoPerspective_Flag) {
2827 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2828 fDecorationBuffer);
2829 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002830 }
2831}
2832
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002833void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002834 for (const auto& stmt : decl.fVars) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002835 SkASSERT(stmt->fKind == Statement::kVarDeclaration_Kind);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002836 VarDeclaration& varDecl = (VarDeclaration&) *stmt;
2837 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002838 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2839 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002840 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002841 Modifiers::kWriteOnly_Flag |
2842 Modifiers::kCoherent_Flag |
2843 Modifiers::kVolatile_Flag |
2844 Modifiers::kRestrict_Flag)));
ethannicholasb3058bd2016-07-01 08:22:01 -07002845 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002846 fVariableMap[var] = id;
2847 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002848 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002849 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002850 if (varDecl.fValue) {
2851 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002852 this->writeInstruction(SpvOpStore, id, value, out);
2853 }
2854 }
2855}
2856
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002857void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002858 switch (s.fKind) {
Ethan Nicholascb670962017-04-20 19:31:52 -04002859 case Statement::kNop_Kind:
2860 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002861 case Statement::kBlock_Kind:
2862 this->writeBlock((Block&) s, out);
2863 break;
2864 case Statement::kExpression_Kind:
2865 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2866 break;
Greg Daniel64773e62016-11-22 09:44:03 -05002867 case Statement::kReturn_Kind:
ethannicholasb3058bd2016-07-01 08:22:01 -07002868 this->writeReturnStatement((ReturnStatement&) s, out);
2869 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002870 case Statement::kVarDeclarations_Kind:
2871 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002872 break;
2873 case Statement::kIf_Kind:
2874 this->writeIfStatement((IfStatement&) s, out);
2875 break;
2876 case Statement::kFor_Kind:
2877 this->writeForStatement((ForStatement&) s, out);
2878 break;
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002879 case Statement::kWhile_Kind:
2880 this->writeWhileStatement((WhileStatement&) s, out);
2881 break;
2882 case Statement::kDo_Kind:
2883 this->writeDoStatement((DoStatement&) s, out);
2884 break;
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002885 case Statement::kSwitch_Kind:
2886 this->writeSwitchStatement((SwitchStatement&) s, out);
2887 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002888 case Statement::kBreak_Kind:
2889 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2890 break;
2891 case Statement::kContinue_Kind:
2892 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2893 break;
2894 case Statement::kDiscard_Kind:
2895 this->writeInstruction(SpvOpKill, out);
2896 break;
2897 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002898#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002899 ABORT("unsupported statement: %s", s.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002900#endif
2901 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002902 }
2903}
2904
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002905void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002906 for (size_t i = 0; i < b.fStatements.size(); i++) {
2907 this->writeStatement(*b.fStatements[i], out);
2908 }
2909}
2910
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002911void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002912 SpvId test = this->writeExpression(*stmt.fTest, out);
2913 SpvId ifTrue = this->nextId();
2914 SpvId ifFalse = this->nextId();
2915 if (stmt.fIfFalse) {
2916 SpvId end = this->nextId();
2917 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2918 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2919 this->writeLabel(ifTrue, out);
2920 this->writeStatement(*stmt.fIfTrue, out);
2921 if (fCurrentBlock) {
2922 this->writeInstruction(SpvOpBranch, end, out);
2923 }
2924 this->writeLabel(ifFalse, out);
2925 this->writeStatement(*stmt.fIfFalse, out);
2926 if (fCurrentBlock) {
2927 this->writeInstruction(SpvOpBranch, end, out);
2928 }
2929 this->writeLabel(end, out);
2930 } else {
2931 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2932 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2933 this->writeLabel(ifTrue, out);
2934 this->writeStatement(*stmt.fIfTrue, out);
2935 if (fCurrentBlock) {
2936 this->writeInstruction(SpvOpBranch, ifFalse, out);
2937 }
2938 this->writeLabel(ifFalse, out);
2939 }
2940}
2941
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002942void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002943 if (f.fInitializer) {
2944 this->writeStatement(*f.fInitializer, out);
2945 }
2946 SpvId header = this->nextId();
2947 SpvId start = this->nextId();
2948 SpvId body = this->nextId();
2949 SpvId next = this->nextId();
2950 fContinueTarget.push(next);
2951 SpvId end = this->nextId();
2952 fBreakTarget.push(end);
2953 this->writeInstruction(SpvOpBranch, header, out);
2954 this->writeLabel(header, out);
2955 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002956 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002957 this->writeLabel(start, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002958 if (f.fTest) {
2959 SpvId test = this->writeExpression(*f.fTest, out);
2960 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2961 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002962 this->writeLabel(body, out);
2963 this->writeStatement(*f.fStatement, out);
2964 if (fCurrentBlock) {
2965 this->writeInstruction(SpvOpBranch, next, out);
2966 }
2967 this->writeLabel(next, out);
2968 if (f.fNext) {
2969 this->writeExpression(*f.fNext, out);
2970 }
2971 this->writeInstruction(SpvOpBranch, header, out);
2972 this->writeLabel(end, out);
2973 fBreakTarget.pop();
2974 fContinueTarget.pop();
2975}
2976
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002977void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002978 SpvId header = this->nextId();
2979 SpvId start = this->nextId();
2980 SpvId body = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04002981 SpvId continueTarget = this->nextId();
2982 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002983 SpvId end = this->nextId();
2984 fBreakTarget.push(end);
2985 this->writeInstruction(SpvOpBranch, header, out);
2986 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04002987 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002988 this->writeInstruction(SpvOpBranch, start, out);
2989 this->writeLabel(start, out);
2990 SpvId test = this->writeExpression(*w.fTest, out);
2991 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2992 this->writeLabel(body, out);
2993 this->writeStatement(*w.fStatement, out);
2994 if (fCurrentBlock) {
Ethan Nicholas0d997662019-04-08 09:46:01 -04002995 this->writeInstruction(SpvOpBranch, continueTarget, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002996 }
Ethan Nicholas0d997662019-04-08 09:46:01 -04002997 this->writeLabel(continueTarget, out);
2998 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002999 this->writeLabel(end, out);
3000 fBreakTarget.pop();
3001 fContinueTarget.pop();
3002}
3003
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003004void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003005 SpvId header = this->nextId();
3006 SpvId start = this->nextId();
3007 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003008 SpvId continueTarget = this->nextId();
3009 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003010 SpvId end = this->nextId();
3011 fBreakTarget.push(end);
3012 this->writeInstruction(SpvOpBranch, header, out);
3013 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003014 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003015 this->writeInstruction(SpvOpBranch, start, out);
3016 this->writeLabel(start, out);
3017 this->writeStatement(*d.fStatement, out);
3018 if (fCurrentBlock) {
3019 this->writeInstruction(SpvOpBranch, next, out);
3020 }
3021 this->writeLabel(next, out);
3022 SpvId test = this->writeExpression(*d.fTest, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003023 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
3024 this->writeLabel(continueTarget, out);
3025 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003026 this->writeLabel(end, out);
3027 fBreakTarget.pop();
3028 fContinueTarget.pop();
3029}
3030
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003031void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
3032 SpvId value = this->writeExpression(*s.fValue, out);
3033 std::vector<SpvId> labels;
3034 SpvId end = this->nextId();
3035 SpvId defaultLabel = end;
3036 fBreakTarget.push(end);
3037 int size = 3;
3038 for (const auto& c : s.fCases) {
3039 SpvId label = this->nextId();
3040 labels.push_back(label);
3041 if (c->fValue) {
3042 size += 2;
3043 } else {
3044 defaultLabel = label;
3045 }
3046 }
3047 labels.push_back(end);
3048 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3049 this->writeOpCode(SpvOpSwitch, size, out);
3050 this->writeWord(value, out);
3051 this->writeWord(defaultLabel, out);
3052 for (size_t i = 0; i < s.fCases.size(); ++i) {
3053 if (!s.fCases[i]->fValue) {
3054 continue;
3055 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003056 SkASSERT(s.fCases[i]->fValue->fKind == Expression::kIntLiteral_Kind);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003057 this->writeWord(((IntLiteral&) *s.fCases[i]->fValue).fValue, out);
3058 this->writeWord(labels[i], out);
3059 }
3060 for (size_t i = 0; i < s.fCases.size(); ++i) {
3061 this->writeLabel(labels[i], out);
3062 for (const auto& stmt : s.fCases[i]->fStatements) {
3063 this->writeStatement(*stmt, out);
3064 }
3065 if (fCurrentBlock) {
3066 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3067 }
3068 }
3069 this->writeLabel(end, out);
3070 fBreakTarget.pop();
3071}
3072
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003073void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003074 if (r.fExpression) {
Greg Daniel64773e62016-11-22 09:44:03 -05003075 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003076 out);
3077 } else {
3078 this->writeInstruction(SpvOpReturn, out);
3079 }
3080}
3081
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003082void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003083 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003084 int invocations = 1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003085 for (const auto& e : fProgram) {
3086 if (e.fKind == ProgramElement::kModifiers_Kind) {
3087 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003088 if (m.fFlags & Modifiers::kIn_Flag) {
3089 if (m.fLayout.fInvocations != -1) {
3090 invocations = m.fLayout.fInvocations;
3091 }
3092 SpvId input;
3093 switch (m.fLayout.fPrimitive) {
3094 case Layout::kPoints_Primitive:
3095 input = SpvExecutionModeInputPoints;
3096 break;
3097 case Layout::kLines_Primitive:
3098 input = SpvExecutionModeInputLines;
3099 break;
3100 case Layout::kLinesAdjacency_Primitive:
3101 input = SpvExecutionModeInputLinesAdjacency;
3102 break;
3103 case Layout::kTriangles_Primitive:
3104 input = SpvExecutionModeTriangles;
3105 break;
3106 case Layout::kTrianglesAdjacency_Primitive:
3107 input = SpvExecutionModeInputTrianglesAdjacency;
3108 break;
3109 default:
3110 input = 0;
3111 break;
3112 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003113 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003114 if (input) {
3115 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3116 }
3117 } else if (m.fFlags & Modifiers::kOut_Flag) {
3118 SpvId output;
3119 switch (m.fLayout.fPrimitive) {
3120 case Layout::kPoints_Primitive:
3121 output = SpvExecutionModeOutputPoints;
3122 break;
3123 case Layout::kLineStrip_Primitive:
3124 output = SpvExecutionModeOutputLineStrip;
3125 break;
3126 case Layout::kTriangleStrip_Primitive:
3127 output = SpvExecutionModeOutputTriangleStrip;
3128 break;
3129 default:
3130 output = 0;
3131 break;
3132 }
3133 if (output) {
3134 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3135 }
3136 if (m.fLayout.fMaxVertices != -1) {
3137 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3138 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3139 out);
3140 }
3141 }
3142 }
3143 }
3144 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3145 invocations, out);
3146}
3147
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003148void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003149 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003150 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003151 std::set<SpvId> interfaceVars;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003152 // assign IDs to functions, determine sk_in size
3153 int skInSize = -1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003154 for (const auto& e : program) {
3155 switch (e.fKind) {
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003156 case ProgramElement::kFunction_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003157 FunctionDefinition& f = (FunctionDefinition&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003158 fFunctionMap[&f.fDeclaration] = this->nextId();
3159 break;
3160 }
3161 case ProgramElement::kModifiers_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003162 Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003163 if (m.fFlags & Modifiers::kIn_Flag) {
3164 switch (m.fLayout.fPrimitive) {
3165 case Layout::kPoints_Primitive: // break
3166 case Layout::kLines_Primitive:
3167 skInSize = 1;
3168 break;
3169 case Layout::kLinesAdjacency_Primitive: // break
3170 skInSize = 2;
3171 break;
3172 case Layout::kTriangles_Primitive: // break
3173 case Layout::kTrianglesAdjacency_Primitive:
3174 skInSize = 3;
3175 break;
3176 default:
3177 break;
3178 }
3179 }
3180 break;
3181 }
3182 default:
3183 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003184 }
3185 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003186 for (const auto& e : program) {
3187 if (e.fKind == ProgramElement::kInterfaceBlock_Kind) {
3188 InterfaceBlock& intf = (InterfaceBlock&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003189 if (SK_IN_BUILTIN == intf.fVariable.fModifiers.fLayout.fBuiltin) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003190 SkASSERT(skInSize != -1);
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003191 intf.fSizes.emplace_back(new IntLiteral(fContext, -1, skInSize));
3192 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003193 SpvId id = this->writeInterfaceBlock(intf);
Ethan Nicholas16c11962018-03-16 12:20:54 -04003194 if (((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
3195 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) &&
Chris Dalton2284aab2019-11-15 11:02:24 -07003196 intf.fVariable.fModifiers.fLayout.fBuiltin == -1 &&
3197 !is_dead(intf.fVariable)) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003198 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003199 }
3200 }
3201 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003202 for (const auto& e : program) {
3203 if (e.fKind == ProgramElement::kVar_Kind) {
3204 this->writeGlobalVars(program.fKind, ((VarDeclarations&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003205 }
3206 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003207 for (const auto& e : program) {
3208 if (e.fKind == ProgramElement::kFunction_Kind) {
3209 this->writeFunction(((FunctionDefinition&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003210 }
3211 }
ethannicholasd598f792016-07-25 10:08:54 -07003212 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003213 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07003214 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003215 main = entry.first;
3216 }
3217 }
Ethan Nicholas1a668d22019-04-18 10:37:40 -04003218 if (!main) {
3219 fErrors.error(0, "program does not contain a main() function");
3220 return;
3221 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003222 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003223 const Variable* var = entry.first;
Greg Daniel64773e62016-11-22 09:44:03 -05003224 if (var->fStorage == Variable::kGlobal_Storage &&
Ethan Nicholas16c11962018-03-16 12:20:54 -04003225 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
Chris Dalton2284aab2019-11-15 11:02:24 -07003226 (var->fModifiers.fFlags & Modifiers::kOut_Flag)) && !is_dead(*var)) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003227 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003228 }
3229 }
3230 this->writeCapabilities(out);
3231 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3232 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003233 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->fName.fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003234 (int32_t) interfaceVars.size(), out);
3235 switch (program.fKind) {
3236 case Program::kVertex_Kind:
3237 this->writeWord(SpvExecutionModelVertex, out);
3238 break;
3239 case Program::kFragment_Kind:
3240 this->writeWord(SpvExecutionModelFragment, out);
3241 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003242 case Program::kGeometry_Kind:
3243 this->writeWord(SpvExecutionModelGeometry, out);
3244 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003245 default:
3246 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003247 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003248 SpvId entryPoint = fFunctionMap[main];
3249 this->writeWord(entryPoint, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003250 this->writeString(main->fName.fChars, main->fName.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003251 for (int var : interfaceVars) {
3252 this->writeWord(var, out);
3253 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003254 if (program.fKind == Program::kGeometry_Kind) {
3255 this->writeGeometryShaderExecutionMode(entryPoint, out);
3256 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003257 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003258 this->writeInstruction(SpvOpExecutionMode,
3259 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003260 SpvExecutionModeOriginUpperLeft,
3261 out);
3262 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003263 for (const auto& e : program) {
3264 if (e.fKind == ProgramElement::kExtension_Kind) {
3265 this->writeInstruction(SpvOpSourceExtension, ((Extension&) e).fName.c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003266 }
3267 }
Greg Daniel64773e62016-11-22 09:44:03 -05003268
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003269 write_stringstream(fExtraGlobalsBuffer, out);
3270 write_stringstream(fNameBuffer, out);
3271 write_stringstream(fDecorationBuffer, out);
3272 write_stringstream(fConstantBuffer, out);
3273 write_stringstream(fExternalFunctionsBuffer, out);
3274 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003275}
3276
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003277bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003278 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003279 this->writeWord(SpvMagicNumber, *fOut);
3280 this->writeWord(SpvVersion, *fOut);
3281 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003282 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003283 this->writeInstructions(fProgram, buffer);
3284 this->writeWord(fIdCount, *fOut);
3285 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003286 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003287 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003288}
3289
3290}