blob: c09871b1bed1b5d3b6b3234242ffb5c61054d310 [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) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400159 if (type.typeKind() == Type::TypeKind::kVector) {
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) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400167 if (type.typeKind() == Type::TypeKind::kVector) {
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) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400175 if (type.typeKind() == Type::TypeKind::kVector) {
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 Nicholase6592142020-09-08 10:22:09 -0400426 if (field.fType->typeKind() == Type::TypeKind::kMatrix) {
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 Nicholase6592142020-09-08 10:22:09 -0400438 Type::TypeKind kind = field.fType->typeKind();
439 if ((kind == Type::TypeKind::kArray || kind == Type::TypeKind::kStruct) &&
440 offset % alignment != 0) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700441 offset += alignment - offset % alignment;
442 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700443 }
444}
445
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400446Type SPIRVCodeGenerator::getActualType(const Type& type) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500447 if (type.isFloat()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400448 return *fContext.fFloat_Type;
449 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500450 if (type.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400451 return *fContext.fInt_Type;
452 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500453 if (type.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400454 return *fContext.fUInt_Type;
455 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400456 if (type.typeKind() == Type::TypeKind::kMatrix || type.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400457 if (type.componentType() == *fContext.fHalf_Type) {
458 return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
459 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400460 if (type.componentType() == *fContext.fShort_Type ||
461 type.componentType() == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400462 return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
463 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400464 if (type.componentType() == *fContext.fUShort_Type ||
465 type.componentType() == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400466 return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
467 }
468 }
469 return type;
470}
471
ethannicholasb3058bd2016-07-01 08:22:01 -0700472SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800473 return this->getType(type, fDefaultLayout);
474}
475
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400476SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
477 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400478 String key = type.name() + to_string((int) layout.fStd);
ethannicholas8ac838d2016-11-22 08:39:36 -0800479 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700480 if (entry == fTypeMap.end()) {
481 SpvId result = this->nextId();
Ethan Nicholase6592142020-09-08 10:22:09 -0400482 switch (type.typeKind()) {
483 case Type::TypeKind::kScalar:
ethannicholasd598f792016-07-25 10:08:54 -0700484 if (type == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700485 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500486 } else if (type == *fContext.fInt_Type || type == *fContext.fShort_Type ||
487 type == *fContext.fIntLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700488 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500489 } else if (type == *fContext.fUInt_Type || type == *fContext.fUShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700490 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500491 } else if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type ||
492 type == *fContext.fFloatLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700493 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700494 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400495 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700496 }
497 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400498 case Type::TypeKind::kVector:
Greg Daniel64773e62016-11-22 09:44:03 -0500499 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800500 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700501 type.columns(), fConstantBuffer);
502 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400503 case Type::TypeKind::kMatrix:
Greg Daniel64773e62016-11-22 09:44:03 -0500504 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800505 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700506 type.columns(), fConstantBuffer);
507 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400508 case Type::TypeKind::kStruct:
ethannicholas8ac838d2016-11-22 08:39:36 -0800509 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700510 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400511 case Type::TypeKind::kArray: {
ethannicholasb3058bd2016-07-01 08:22:01 -0700512 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700513 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500514 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800515 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700516 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500517 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400518 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800519 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700520 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400521 SkASSERT(false); // we shouldn't have any runtime-sized arrays right now
Greg Daniel64773e62016-11-22 09:44:03 -0500522 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800523 this->getType(type.componentType(), layout),
524 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400525 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
526 (int32_t) layout.stride(type),
527 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700528 }
529 break;
530 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400531 case Type::TypeKind::kSampler: {
Greg Daniel64773e62016-11-22 09:44:03 -0500532 SpvId image = result;
533 if (SpvDimSubpassData != type.dimensions()) {
Stephen White792e2302019-08-09 13:33:51 -0400534 image = this->getType(type.textureType(), layout);
Greg Daniel64773e62016-11-22 09:44:03 -0500535 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400536 if (SpvDimBuffer == type.dimensions()) {
537 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
538 }
Greg Daniel64773e62016-11-22 09:44:03 -0500539 if (SpvDimSubpassData != type.dimensions()) {
540 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
541 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700542 break;
543 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400544 case Type::TypeKind::kSeparateSampler: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400545 this->writeInstruction(SpvOpTypeSampler, result, fConstantBuffer);
546 break;
547 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400548 case Type::TypeKind::kTexture: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400549 this->writeInstruction(SpvOpTypeImage, result,
550 this->getType(*fContext.fFloat_Type, layout),
Stephen White792e2302019-08-09 13:33:51 -0400551 type.dimensions(), type.isDepth(), type.isArrayed(),
552 type.isMultisampled(), type.isSampled() ? 1 : 2,
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400553 SpvImageFormatUnknown, fConstantBuffer);
554 fImageTypeMap[key] = result;
555 break;
556 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700557 default:
ethannicholasd598f792016-07-25 10:08:54 -0700558 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700559 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
560 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500561#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700562 ABORT("invalid type: %s", type.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500563#endif
ethannicholasb3058bd2016-07-01 08:22:01 -0700564 }
565 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800566 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700567 return result;
568 }
569 return entry->second;
570}
571
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400572SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400573 SkASSERT(type.typeKind() == Type::TypeKind::kSampler);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400574 this->getType(type);
575 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400576 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400577 return fImageTypeMap[key];
578}
579
ethannicholasd598f792016-07-25 10:08:54 -0700580SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Brian Osmanc4f937b2020-03-25 15:39:07 -0400581 String key = to_string(this->getType(function.fReturnType)) + "(";
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400582 String separator;
ethannicholasd598f792016-07-25 10:08:54 -0700583 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700584 key += separator;
585 separator = ", ";
Brian Osmanc4f937b2020-03-25 15:39:07 -0400586 key += to_string(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700587 }
588 key += ")";
589 auto entry = fTypeMap.find(key);
590 if (entry == fTypeMap.end()) {
591 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -0700592 int32_t length = 3 + (int32_t) function.fParameters.size();
593 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700594 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -0700595 for (size_t i = 0; i < function.fParameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500596 // glslang seems to treat all function arguments as pointers whether they need to be or
597 // not. I was initially puzzled by this until I ran bizarre failures with certain
598 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700599 // failure case:
600 //
601 // void sphere(float x) {
602 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500603 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700604 // void map() {
605 // sphere(1.0);
606 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500607 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700608 // void main() {
609 // for (int i = 0; i < 1; i++) {
610 // map();
611 // }
612 // }
613 //
Greg Daniel64773e62016-11-22 09:44:03 -0500614 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
615 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700616 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
617 // the spec makes this make sense.
618// if (is_out(function->fParameters[i])) {
ethannicholasd598f792016-07-25 10:08:54 -0700619 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -0700620 SpvStorageClassFunction));
621// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700622// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700623// }
624 }
625 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
626 this->writeWord(result, fConstantBuffer);
627 this->writeWord(returnType, fConstantBuffer);
628 for (SpvId id : parameterTypes) {
629 this->writeWord(id, fConstantBuffer);
630 }
631 fTypeMap[key] = result;
632 return result;
633 }
634 return entry->second;
635}
636
ethannicholas8ac838d2016-11-22 08:39:36 -0800637SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
638 return this->getPointerType(type, fDefaultLayout, storageClass);
639}
640
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400641SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700642 SpvStorageClass_ storageClass) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400643 Type type = this->getActualType(rawType);
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500644 String key = type.displayName() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700645 auto entry = fTypeMap.find(key);
646 if (entry == fTypeMap.end()) {
647 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500648 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700649 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700650 fTypeMap[key] = result;
651 return result;
652 }
653 return entry->second;
654}
655
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400656SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400657 switch (expr.kind()) {
658 case Expression::Kind::kBinary:
John Stiles81365af2020-08-18 09:24:00 -0400659 return this->writeBinaryExpression(expr.as<BinaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400660 case Expression::Kind::kBoolLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400661 return this->writeBoolLiteral(expr.as<BoolLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400662 case Expression::Kind::kConstructor:
John Stiles81365af2020-08-18 09:24:00 -0400663 return this->writeConstructor(expr.as<Constructor>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400664 case Expression::Kind::kIntLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400665 return this->writeIntLiteral(expr.as<IntLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400666 case Expression::Kind::kFieldAccess:
John Stiles81365af2020-08-18 09:24:00 -0400667 return this->writeFieldAccess(expr.as<FieldAccess>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400668 case Expression::Kind::kFloatLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400669 return this->writeFloatLiteral(expr.as<FloatLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400670 case Expression::Kind::kFunctionCall:
John Stiles81365af2020-08-18 09:24:00 -0400671 return this->writeFunctionCall(expr.as<FunctionCall>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400672 case Expression::Kind::kPrefix:
John Stiles81365af2020-08-18 09:24:00 -0400673 return this->writePrefixExpression(expr.as<PrefixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400674 case Expression::Kind::kPostfix:
John Stiles81365af2020-08-18 09:24:00 -0400675 return this->writePostfixExpression(expr.as<PostfixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400676 case Expression::Kind::kSwizzle:
John Stiles81365af2020-08-18 09:24:00 -0400677 return this->writeSwizzle(expr.as<Swizzle>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400678 case Expression::Kind::kVariableReference:
John Stiles81365af2020-08-18 09:24:00 -0400679 return this->writeVariableReference(expr.as<VariableReference>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400680 case Expression::Kind::kTernary:
John Stiles81365af2020-08-18 09:24:00 -0400681 return this->writeTernaryExpression(expr.as<TernaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400682 case Expression::Kind::kIndex:
John Stiles81365af2020-08-18 09:24:00 -0400683 return this->writeIndexExpression(expr.as<IndexExpression>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700684 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500685#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700686 ABORT("unsupported expression: %s", expr.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500687#endif
688 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700689 }
690 return -1;
691}
692
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400693SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700694 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400695 SkASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -0700696 int32_t intrinsicId;
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400697 if (c.fArguments.size() > 0) {
698 const Type& type = c.fArguments[0]->fType;
699 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
700 intrinsicId = std::get<1>(intrinsic->second);
701 } else if (is_signed(fContext, type)) {
702 intrinsicId = std::get<2>(intrinsic->second);
703 } else if (is_unsigned(fContext, type)) {
704 intrinsicId = std::get<3>(intrinsic->second);
705 } else if (is_bool(fContext, type)) {
706 intrinsicId = std::get<4>(intrinsic->second);
707 } else {
708 intrinsicId = std::get<1>(intrinsic->second);
709 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700710 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400711 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700712 }
713 switch (std::get<0>(intrinsic->second)) {
714 case kGLSL_STD_450_IntrinsicKind: {
715 SpvId result = this->nextId();
716 std::vector<SpvId> arguments;
717 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400718 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
719 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
720 } else {
721 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
722 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700723 }
724 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700725 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700726 this->writeWord(result, out);
727 this->writeWord(fGLSLExtendedInstructions, out);
728 this->writeWord(intrinsicId, out);
729 for (SpvId id : arguments) {
730 this->writeWord(id, out);
731 }
732 return result;
733 }
734 case kSPIRV_IntrinsicKind: {
735 SpvId result = this->nextId();
736 std::vector<SpvId> arguments;
737 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400738 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
739 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
740 } else {
741 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
742 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700743 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400744 if (c.fType != *fContext.fVoid_Type) {
745 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
746 this->writeWord(this->getType(c.fType), out);
747 this->writeWord(result, out);
748 } else {
749 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
750 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700751 for (SpvId id : arguments) {
752 this->writeWord(id, out);
753 }
754 return result;
755 }
756 case kSpecial_IntrinsicKind:
757 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
758 default:
759 ABORT("unsupported intrinsic kind");
760 }
761}
762
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500763std::vector<SpvId> SPIRVCodeGenerator::vectorize(
764 const std::vector<std::unique_ptr<Expression>>& args,
765 OutputStream& out) {
766 int vectorSize = 0;
767 for (const auto& a : args) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400768 if (a->fType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500769 if (vectorSize) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400770 SkASSERT(a->fType.columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500771 }
772 else {
773 vectorSize = a->fType.columns();
774 }
775 }
776 }
777 std::vector<SpvId> result;
778 for (const auto& a : args) {
779 SpvId raw = this->writeExpression(*a, out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400780 if (vectorSize && a->fType.typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500781 SpvId vector = this->nextId();
782 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
783 this->writeWord(this->getType(a->fType.toCompound(fContext, vectorSize, 1)), out);
784 this->writeWord(vector, out);
785 for (int i = 0; i < vectorSize; i++) {
786 this->writeWord(raw, out);
787 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400788 this->writePrecisionModifier(a->fType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500789 result.push_back(vector);
790 } else {
791 result.push_back(raw);
792 }
793 }
794 return result;
795}
796
797void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
798 SpvId signedInst, SpvId unsignedInst,
799 const std::vector<SpvId>& args,
800 OutputStream& out) {
801 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
802 this->writeWord(this->getType(type), out);
803 this->writeWord(id, out);
804 this->writeWord(fGLSLExtendedInstructions, out);
805
806 if (is_float(fContext, type)) {
807 this->writeWord(floatInst, out);
808 } else if (is_signed(fContext, type)) {
809 this->writeWord(signedInst, out);
810 } else if (is_unsigned(fContext, type)) {
811 this->writeWord(unsignedInst, out);
812 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400813 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500814 }
815 for (SpvId a : args) {
816 this->writeWord(a, out);
817 }
818}
819
Greg Daniel64773e62016-11-22 09:44:03 -0500820SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400821 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700822 SpvId result = this->nextId();
823 switch (kind) {
824 case kAtan_SpecialIntrinsic: {
825 std::vector<SpvId> arguments;
826 for (size_t i = 0; i < c.fArguments.size(); i++) {
827 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
828 }
829 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700830 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700831 this->writeWord(result, out);
832 this->writeWord(fGLSLExtendedInstructions, out);
833 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
834 for (SpvId id : arguments) {
835 this->writeWord(id, out);
836 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400837 break;
838 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400839 case kSampledImage_SpecialIntrinsic: {
840 SkASSERT(2 == c.fArguments.size());
841 SpvId img = this->writeExpression(*c.fArguments[0], out);
842 SpvId sampler = this->writeExpression(*c.fArguments[1], out);
843 this->writeInstruction(SpvOpSampledImage,
844 this->getType(c.fType),
845 result,
846 img,
847 sampler,
848 out);
849 break;
850 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400851 case kSubpassLoad_SpecialIntrinsic: {
852 SpvId img = this->writeExpression(*c.fArguments[0], out);
853 std::vector<std::unique_ptr<Expression>> args;
Greg Danielcf1a4f52020-09-08 15:25:23 -0400854 args.emplace_back(new IntLiteral(fContext, -1, 0));
855 args.emplace_back(new IntLiteral(fContext, -1, 0));
856 Constructor ctor(-1, *fContext.fInt2_Type, std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400857 SpvId coords = this->writeConstantVector(ctor);
858 if (1 == c.fArguments.size()) {
859 this->writeInstruction(SpvOpImageRead,
860 this->getType(c.fType),
861 result,
862 img,
863 coords,
864 out);
865 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400866 SkASSERT(2 == c.fArguments.size());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400867 SpvId sample = this->writeExpression(*c.fArguments[1], out);
868 this->writeInstruction(SpvOpImageRead,
869 this->getType(c.fType),
870 result,
871 img,
872 coords,
873 SpvImageOperandsSampleMask,
874 sample,
875 out);
876 }
877 break;
878 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700879 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500880 SpvOp_ op = SpvOpImageSampleImplicitLod;
881 switch (c.fArguments[0]->fType.dimensions()) {
882 case SpvDim1D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400883 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500884 op = SpvOpImageSampleProjImplicitLod;
885 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400886 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500887 }
888 break;
889 case SpvDim2D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400890 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500891 op = SpvOpImageSampleProjImplicitLod;
892 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400893 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500894 }
895 break;
896 case SpvDim3D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400897 if (c.fArguments[1]->fType == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500898 op = SpvOpImageSampleProjImplicitLod;
899 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400900 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500901 }
902 break;
903 case SpvDimCube: // fall through
904 case SpvDimRect: // fall through
905 case SpvDimBuffer: // fall through
906 case SpvDimSubpassData:
907 break;
908 }
ethannicholasd598f792016-07-25 10:08:54 -0700909 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700910 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
911 SpvId uv = this->writeExpression(*c.fArguments[1], out);
912 if (c.fArguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500913 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700914 SpvImageOperandsBiasMask,
915 this->writeExpression(*c.fArguments[2], out),
916 out);
917 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400918 SkASSERT(c.fArguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500919 if (fProgram.fSettings.fSharpenTextures) {
920 FloatLiteral lodBias(fContext, -1, -0.5);
921 this->writeInstruction(op, type, result, sampler, uv,
922 SpvImageOperandsBiasMask,
923 this->writeFloatLiteral(lodBias),
924 out);
925 } else {
926 this->writeInstruction(op, type, result, sampler, uv,
927 out);
928 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700929 }
930 break;
931 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500932 case kMod_SpecialIntrinsic: {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500933 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400934 SkASSERT(args.size() == 2);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500935 const Type& operandType = c.fArguments[0]->fType;
936 SpvOp_ op;
937 if (is_float(fContext, operandType)) {
938 op = SpvOpFMod;
939 } else if (is_signed(fContext, operandType)) {
940 op = SpvOpSMod;
941 } else if (is_unsigned(fContext, operandType)) {
942 op = SpvOpUMod;
943 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400944 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500945 return 0;
946 }
947 this->writeOpCode(op, 5, out);
948 this->writeWord(this->getType(operandType), out);
949 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500950 this->writeWord(args[0], out);
951 this->writeWord(args[1], out);
952 break;
953 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700954 case kDFdy_SpecialIntrinsic: {
955 SpvId fn = this->writeExpression(*c.fArguments[0], out);
956 this->writeOpCode(SpvOpDPdy, 4, out);
957 this->writeWord(this->getType(c.fType), out);
958 this->writeWord(result, out);
959 this->writeWord(fn, out);
960 if (fProgram.fSettings.fFlipY) {
961 // Flipping Y also negates the Y derivatives.
962 SpvId flipped = this->nextId();
963 this->writeInstruction(SpvOpFNegate, this->getType(c.fType), flipped, result, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -0400964 this->writePrecisionModifier(c.fType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700965 return flipped;
966 }
967 break;
968 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500969 case kClamp_SpecialIntrinsic: {
970 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400971 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500972 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
973 GLSLstd450UClamp, args, out);
974 break;
975 }
976 case kMax_SpecialIntrinsic: {
977 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400978 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500979 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMax, GLSLstd450SMax,
980 GLSLstd450UMax, args, out);
981 break;
982 }
983 case kMin_SpecialIntrinsic: {
984 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400985 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500986 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMin, GLSLstd450SMin,
987 GLSLstd450UMin, args, out);
988 break;
989 }
990 case kMix_SpecialIntrinsic: {
991 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400992 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500993 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMix, SpvOpUndef,
994 SpvOpUndef, args, out);
995 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500996 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400997 case kSaturate_SpecialIntrinsic: {
998 SkASSERT(c.fArguments.size() == 1);
999 std::vector<std::unique_ptr<Expression>> finalArgs;
1000 finalArgs.push_back(c.fArguments[0]->clone());
1001 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 0));
1002 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 1));
1003 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
1004 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
1005 GLSLstd450UClamp, spvArgs, out);
1006 break;
1007 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001008 }
1009 return result;
1010}
1011
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001012SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001013 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07001014 if (entry == fFunctionMap.end()) {
1015 return this->writeIntrinsicCall(c, out);
1016 }
1017 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001018 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
ethannicholasb3058bd2016-07-01 08:22:01 -07001019 std::vector<SpvId> arguments;
1020 for (size_t i = 0; i < c.fArguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001021 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001022 // passed directly
1023 SpvId tmpVar;
1024 // if we need a temporary var to store this argument, this is the value to store in the var
1025 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -07001026 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001027 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
1028 SpvId ptr = lv->getPointer();
1029 if (ptr) {
1030 arguments.push_back(ptr);
1031 continue;
1032 } else {
1033 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1034 // copy it into a temp, call the function, read the value out of the temp, and then
1035 // update the lvalue.
1036 tmpValueId = lv->load(out);
1037 tmpVar = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001038 lvalues.push_back(std::make_tuple(tmpVar, &c.fArguments[i]->fType, std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001039 }
1040 } else {
1041 // see getFunctionType for an explanation of why we're always using pointer parameters
1042 tmpValueId = this->writeExpression(*c.fArguments[i], out);
1043 tmpVar = this->nextId();
1044 }
Greg Daniel64773e62016-11-22 09:44:03 -05001045 this->writeInstruction(SpvOpVariable,
1046 this->getPointerType(c.fArguments[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -07001047 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001048 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001049 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001050 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001051 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1052 arguments.push_back(tmpVar);
1053 }
1054 SpvId result = this->nextId();
1055 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001056 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001057 this->writeWord(result, out);
1058 this->writeWord(entry->second, out);
1059 for (SpvId id : arguments) {
1060 this->writeWord(id, out);
1061 }
1062 // now that the call is complete, we may need to update some lvalues with the new values of out
1063 // arguments
1064 for (const auto& tuple : lvalues) {
1065 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001066 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1067 out);
1068 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001069 std::get<2>(tuple)->store(load, out);
1070 }
1071 return result;
1072}
1073
ethannicholasf789b382016-08-03 12:43:36 -07001074SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001075 SkASSERT(c.fType.typeKind() == Type::TypeKind::kVector && c.isCompileTimeConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001076 SpvId result = this->nextId();
1077 std::vector<SpvId> arguments;
1078 for (size_t i = 0; i < c.fArguments.size(); i++) {
1079 arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1080 }
ethannicholasd598f792016-07-25 10:08:54 -07001081 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001082 if (c.fArguments.size() == 1) {
1083 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001084 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001085 this->writeWord(type, fConstantBuffer);
1086 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001087 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001088 this->writeWord(arguments[0], fConstantBuffer);
1089 }
1090 } else {
Greg Daniel64773e62016-11-22 09:44:03 -05001091 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001092 fConstantBuffer);
1093 this->writeWord(type, fConstantBuffer);
1094 this->writeWord(result, fConstantBuffer);
1095 for (SpvId id : arguments) {
1096 this->writeWord(id, fConstantBuffer);
1097 }
1098 }
1099 return result;
1100}
1101
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001102SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001103 SkASSERT(c.fType.isFloat());
1104 SkASSERT(c.fArguments.size() == 1);
1105 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001106 SpvId result = this->nextId();
1107 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001108 if (c.fArguments[0]->fType.isSigned()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001109 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001110 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001111 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001112 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Greg Daniel64773e62016-11-22 09:44:03 -05001113 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001114 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001115 }
1116 return result;
1117}
1118
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001119SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001120 SkASSERT(c.fType.isSigned());
1121 SkASSERT(c.fArguments.size() == 1);
1122 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001123 SpvId result = this->nextId();
1124 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001125 if (c.fArguments[0]->fType.isFloat()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001126 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001127 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001128 }
1129 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001130 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001131 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001132 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001133 }
1134 return result;
1135}
1136
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001137SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001138 SkASSERT(c.fType.isUnsigned());
1139 SkASSERT(c.fArguments.size() == 1);
1140 SkASSERT(c.fArguments[0]->fType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001141 SpvId result = this->nextId();
1142 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001143 if (c.fArguments[0]->fType.isFloat()) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001144 this->writeInstruction(SpvOpConvertFToU, this->getType(c.fType), result, parameter,
1145 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001146 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001147 SkASSERT(c.fArguments[0]->fType.isSigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001148 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
1149 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001150 }
1151 return result;
1152}
1153
Ethan Nicholas84645e32017-02-09 13:57:14 -05001154void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001155 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001156 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001157 SpvId zeroId = this->writeFloatLiteral(zero);
1158 std::vector<SpvId> columnIds;
1159 for (int column = 0; column < type.columns(); column++) {
1160 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1161 out);
1162 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1163 out);
1164 SpvId columnId = this->nextId();
1165 this->writeWord(columnId, out);
1166 columnIds.push_back(columnId);
1167 for (int row = 0; row < type.columns(); row++) {
1168 this->writeWord(row == column ? diagonal : zeroId, out);
1169 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001170 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001171 }
1172 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1173 out);
1174 this->writeWord(this->getType(type), out);
1175 this->writeWord(id, out);
John Stilesf621e232020-08-25 13:33:02 -04001176 for (SpvId columnId : columnIds) {
1177 this->writeWord(columnId, out);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001178 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001179 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001180}
1181
1182void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001183 const Type& dstType, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001184 SkASSERT(srcType.typeKind() == Type::TypeKind::kMatrix);
1185 SkASSERT(dstType.typeKind() == Type::TypeKind::kMatrix);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001186 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001187 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1188 srcType.rows(),
1189 1));
1190 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1191 dstType.rows(),
1192 1));
1193 SpvId zeroId;
1194 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001195 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001196 zeroId = this->writeFloatLiteral(zero);
1197 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001198 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001199 zeroId = this->writeIntLiteral(zero);
1200 } else {
1201 ABORT("unsupported matrix component type");
1202 }
1203 SpvId zeroColumn = 0;
1204 SpvId columns[4];
1205 for (int i = 0; i < dstType.columns(); i++) {
1206 if (i < srcType.columns()) {
1207 // we're still inside the src matrix, copy the column
1208 SpvId srcColumn = this->nextId();
1209 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001210 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001211 SpvId dstColumn;
1212 if (srcType.rows() == dstType.rows()) {
1213 // columns are equal size, don't need to do anything
1214 dstColumn = srcColumn;
1215 }
1216 else if (dstType.rows() > srcType.rows()) {
1217 // dst column is bigger, need to zero-pad it
1218 dstColumn = this->nextId();
1219 int delta = dstType.rows() - srcType.rows();
1220 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1221 this->writeWord(dstColumnType, out);
1222 this->writeWord(dstColumn, out);
1223 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001224 for (int j = 0; j < delta; ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001225 this->writeWord(zeroId, out);
1226 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001227 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001228 }
1229 else {
1230 // dst column is smaller, need to swizzle the src column
1231 dstColumn = this->nextId();
1232 int count = dstType.rows();
1233 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1234 this->writeWord(dstColumnType, out);
1235 this->writeWord(dstColumn, out);
1236 this->writeWord(srcColumn, out);
1237 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001238 for (int j = 0; j < count; j++) {
1239 this->writeWord(j, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001240 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001241 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001242 }
1243 columns[i] = dstColumn;
1244 } else {
1245 // we're past the end of the src matrix, need a vector of zeroes
1246 if (!zeroColumn) {
1247 zeroColumn = this->nextId();
1248 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1249 this->writeWord(dstColumnType, out);
1250 this->writeWord(zeroColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001251 for (int j = 0; j < dstType.rows(); ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001252 this->writeWord(zeroId, out);
1253 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001254 this->writePrecisionModifier(dstType, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001255 }
1256 columns[i] = zeroColumn;
1257 }
1258 }
1259 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1260 this->writeWord(this->getType(dstType), out);
1261 this->writeWord(id, out);
1262 for (int i = 0; i < dstType.columns(); i++) {
1263 this->writeWord(columns[i], out);
1264 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001265 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001266}
1267
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001268void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1269 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001270 std::vector<SpvId>* columnIds,
1271 int* currentCount, int rows, SpvId entry,
1272 OutputStream& out) {
1273 SkASSERT(*currentCount < rows);
1274 ++(*currentCount);
1275 currentColumn->push_back(entry);
1276 if (*currentCount == rows) {
1277 *currentCount = 0;
1278 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1279 this->writeWord(columnType, out);
1280 SpvId columnId = this->nextId();
1281 this->writeWord(columnId, out);
1282 columnIds->push_back(columnId);
1283 for (SpvId id : *currentColumn) {
1284 this->writeWord(id, out);
1285 }
1286 currentColumn->clear();
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001287 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001288 }
1289}
1290
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001291SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001292 SkASSERT(c.fType.typeKind() == Type::TypeKind::kMatrix);
ethannicholasb3058bd2016-07-01 08:22:01 -07001293 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1294 // an instruction
1295 std::vector<SpvId> arguments;
1296 for (size_t i = 0; i < c.fArguments.size(); i++) {
1297 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1298 }
1299 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001300 int rows = c.fType.rows();
1301 int columns = c.fType.columns();
Ethan Nicholase6592142020-09-08 10:22:09 -04001302 if (arguments.size() == 1 && c.fArguments[0]->fType.typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas84645e32017-02-09 13:57:14 -05001303 this->writeUniformScaleMatrix(result, arguments[0], c.fType, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001304 } else if (arguments.size() == 1 &&
1305 c.fArguments[0]->fType.typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas84645e32017-02-09 13:57:14 -05001306 this->writeMatrixCopy(result, arguments[0], c.fArguments[0]->fType, c.fType, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001307 } else if (arguments.size() == 1 &&
1308 c.fArguments[0]->fType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001309 SkASSERT(c.fType.rows() == 2 && c.fType.columns() == 2);
1310 SkASSERT(c.fArguments[0]->fType.columns() == 4);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001311 SpvId componentType = this->getType(c.fType.componentType());
1312 SpvId v[4];
1313 for (int i = 0; i < 4; ++i) {
1314 v[i] = this->nextId();
1315 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i, out);
1316 }
1317 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, 2, 1));
1318 SpvId column1 = this->nextId();
1319 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1320 SpvId column2 = this->nextId();
1321 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
1322 this->writeInstruction(SpvOpCompositeConstruct, this->getType(c.fType), result, column1,
1323 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001324 } else {
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001325 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001326 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001327 // ids of vectors and scalars we have written to the current column so far
1328 std::vector<SpvId> currentColumn;
1329 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001330 int currentCount = 0;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001331 Precision precision = c.fType.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001332 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001333 if (currentCount == 0 &&
1334 c.fArguments[i]->fType.typeKind() == Type::TypeKind::kVector &&
1335 c.fArguments[i]->fType.columns() == c.fType.rows()) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001336 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001337 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001338 } else {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001339 if (c.fArguments[i]->fType.columns() == 1) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001340 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1341 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001342 } else {
1343 SpvId componentType = this->getType(c.fArguments[i]->fType.componentType());
Ethan Nicholas811b9442018-05-11 13:16:03 -04001344 for (int j = 0; j < c.fArguments[i]->fType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001345 SpvId swizzle = this->nextId();
1346 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1347 arguments[i], j, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001348 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1349 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001350 }
1351 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001352 }
1353 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001354 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001355 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001356 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001357 this->writeWord(result, out);
1358 for (SpvId id : columnIds) {
1359 this->writeWord(id, out);
1360 }
1361 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001362 this->writePrecisionModifier(c.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001363 return result;
1364}
1365
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001366SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001367 SkASSERT(c.fType.typeKind() == Type::TypeKind::kVector);
Brian Osmanb6b95732020-06-30 11:44:27 -04001368 if (c.isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001369 return this->writeConstantVector(c);
1370 }
1371 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1372 // an instruction
1373 std::vector<SpvId> arguments;
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001374 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001375 if (c.fArguments[i]->fType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001376 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1377 // extract the components and convert them in that case manually. On top of that,
1378 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1379 // doesn't handle vector arguments at all, so we always extract vector components and
1380 // pass them into OpCreateComposite individually.
1381 SpvId vec = this->writeExpression(*c.fArguments[i], out);
1382 SpvOp_ op = SpvOpUndef;
1383 const Type& src = c.fArguments[i]->fType.componentType();
1384 const Type& dst = c.fType.componentType();
1385 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1386 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1387 if (c.fArguments.size() == 1) {
1388 return vec;
1389 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001390 } else if (src == *fContext.fInt_Type ||
1391 src == *fContext.fShort_Type ||
1392 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001393 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001394 } else if (src == *fContext.fUInt_Type ||
1395 src == *fContext.fUShort_Type ||
1396 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001397 op = SpvOpConvertUToF;
1398 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001399 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001400 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001401 } else if (dst == *fContext.fInt_Type ||
1402 dst == *fContext.fShort_Type ||
1403 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001404 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1405 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001406 } else if (src == *fContext.fInt_Type ||
1407 src == *fContext.fShort_Type ||
1408 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001409 if (c.fArguments.size() == 1) {
1410 return vec;
1411 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001412 } else if (src == *fContext.fUInt_Type ||
1413 src == *fContext.fUShort_Type ||
1414 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001415 op = SpvOpBitcast;
1416 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001417 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001418 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001419 } else if (dst == *fContext.fUInt_Type ||
1420 dst == *fContext.fUShort_Type ||
1421 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001422 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1423 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001424 } else if (src == *fContext.fInt_Type ||
1425 src == *fContext.fShort_Type ||
1426 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001427 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001428 } else if (src == *fContext.fUInt_Type ||
1429 src == *fContext.fUShort_Type ||
1430 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001431 if (c.fArguments.size() == 1) {
1432 return vec;
1433 }
1434 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001435 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001436 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001437 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001438 for (int j = 0; j < c.fArguments[i]->fType.columns(); j++) {
1439 SpvId swizzle = this->nextId();
1440 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1441 out);
1442 if (op != SpvOpUndef) {
1443 SpvId cast = this->nextId();
1444 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1445 arguments.push_back(cast);
1446 } else {
1447 arguments.push_back(swizzle);
1448 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001449 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001450 } else {
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001451 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1452 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001453 }
1454 SpvId result = this->nextId();
Ethan Nicholase6592142020-09-08 10:22:09 -04001455 if (arguments.size() == 1 && c.fArguments[0]->fType.typeKind() == Type::TypeKind::kScalar) {
ethannicholasd598f792016-07-25 10:08:54 -07001456 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1457 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001458 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001459 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001460 this->writeWord(arguments[0], out);
1461 }
1462 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001463 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001464 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001465 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001466 this->writeWord(result, out);
1467 for (SpvId id : arguments) {
1468 this->writeWord(id, out);
1469 }
1470 }
1471 return result;
1472}
1473
Ethan Nicholasbd553222017-07-18 15:54:59 -04001474SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001475 SkASSERT(c.fType.typeKind() == Type::TypeKind::kArray);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001476 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1477 // an instruction
1478 std::vector<SpvId> arguments;
1479 for (size_t i = 0; i < c.fArguments.size(); i++) {
1480 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1481 }
1482 SpvId result = this->nextId();
1483 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
1484 this->writeWord(this->getType(c.fType), out);
1485 this->writeWord(result, out);
1486 for (SpvId id : arguments) {
1487 this->writeWord(id, out);
1488 }
1489 return result;
1490}
1491
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001492SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001493 if (c.fArguments.size() == 1 &&
1494 this->getActualType(c.fType) == this->getActualType(c.fArguments[0]->fType)) {
1495 return this->writeExpression(*c.fArguments[0], out);
1496 }
1497 if (c.fType == *fContext.fFloat_Type || c.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001498 return this->writeFloatConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001499 } else if (c.fType == *fContext.fInt_Type ||
1500 c.fType == *fContext.fShort_Type ||
1501 c.fType == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001502 return this->writeIntConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001503 } else if (c.fType == *fContext.fUInt_Type ||
1504 c.fType == *fContext.fUShort_Type ||
1505 c.fType == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001506 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001507 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001508 switch (c.fType.typeKind()) {
1509 case Type::TypeKind::kVector:
ethannicholasb3058bd2016-07-01 08:22:01 -07001510 return this->writeVectorConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001511 case Type::TypeKind::kMatrix:
ethannicholasb3058bd2016-07-01 08:22:01 -07001512 return this->writeMatrixConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001513 case Type::TypeKind::kArray:
Ethan Nicholasbd553222017-07-18 15:54:59 -04001514 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001515 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001516#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07001517 ABORT("unsupported constructor: %s", c.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001518#endif
1519 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001520 }
1521}
1522
1523SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1524 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001525 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001526 return SpvStorageClassInput;
1527 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001528 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001529 return SpvStorageClassOutput;
1530 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001531 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001532 return SpvStorageClassPushConstant;
1533 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001534 return SpvStorageClassUniform;
1535 } else {
1536 return SpvStorageClassFunction;
1537 }
1538}
1539
ethannicholasf789b382016-08-03 12:43:36 -07001540SpvStorageClass_ get_storage_class(const Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001541 switch (expr.kind()) {
1542 case Expression::Kind::kVariableReference: {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001543 const Variable& var = ((VariableReference&) expr).fVariable;
1544 if (var.fStorage != Variable::kGlobal_Storage) {
1545 return SpvStorageClassFunction;
1546 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001547 SpvStorageClass_ result = get_storage_class(var.fModifiers);
1548 if (result == SpvStorageClassFunction) {
1549 result = SpvStorageClassPrivate;
1550 }
1551 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001552 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001553 case Expression::Kind::kFieldAccess:
ethannicholasb3058bd2016-07-01 08:22:01 -07001554 return get_storage_class(*((FieldAccess&) expr).fBase);
Ethan Nicholase6592142020-09-08 10:22:09 -04001555 case Expression::Kind::kIndex:
ethannicholasb3058bd2016-07-01 08:22:01 -07001556 return get_storage_class(*((IndexExpression&) expr).fBase);
1557 default:
1558 return SpvStorageClassFunction;
1559 }
1560}
1561
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001562std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001563 std::vector<SpvId> chain;
Ethan Nicholase6592142020-09-08 10:22:09 -04001564 switch (expr.kind()) {
1565 case Expression::Kind::kIndex: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001566 IndexExpression& indexExpr = (IndexExpression&) expr;
1567 chain = this->getAccessChain(*indexExpr.fBase, out);
1568 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1569 break;
1570 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001571 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001572 FieldAccess& fieldExpr = (FieldAccess&) expr;
1573 chain = this->getAccessChain(*fieldExpr.fBase, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001574 IntLiteral index(fContext, -1, fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001575 chain.push_back(this->writeIntLiteral(index));
1576 break;
1577 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001578 default: {
1579 SpvId id = this->getLValue(expr, out)->getPointer();
1580 SkASSERT(id != 0);
1581 chain.push_back(id);
1582 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001583 }
1584 return chain;
1585}
1586
1587class PointerLValue : public SPIRVCodeGenerator::LValue {
1588public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001589 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1590 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001591 : fGen(gen)
1592 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001593 , fType(type)
1594 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001595
John Stiles1cf2c8d2020-08-13 22:58:04 -04001596 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001597 return fPointer;
1598 }
1599
John Stiles1cf2c8d2020-08-13 22:58:04 -04001600 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001601 SpvId result = fGen.nextId();
1602 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001603 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001604 return result;
1605 }
1606
John Stiles1cf2c8d2020-08-13 22:58:04 -04001607 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001608 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1609 }
1610
1611private:
1612 SPIRVCodeGenerator& fGen;
1613 const SpvId fPointer;
1614 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001615 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001616};
1617
1618class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1619public:
Greg Daniel64773e62016-11-22 09:44:03 -05001620 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001621 const Type& baseType, const Type& swizzleType,
1622 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001623 : fGen(gen)
1624 , fVecPointer(vecPointer)
1625 , fComponents(components)
1626 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001627 , fSwizzleType(swizzleType)
1628 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001629
John Stiles1cf2c8d2020-08-13 22:58:04 -04001630 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001631 return 0;
1632 }
1633
John Stiles1cf2c8d2020-08-13 22:58:04 -04001634 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001635 SpvId base = fGen.nextId();
1636 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001637 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001638 SpvId result = fGen.nextId();
1639 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1640 fGen.writeWord(fGen.getType(fSwizzleType), out);
1641 fGen.writeWord(result, out);
1642 fGen.writeWord(base, out);
1643 fGen.writeWord(base, out);
1644 for (int component : fComponents) {
1645 fGen.writeWord(component, out);
1646 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001647 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001648 return result;
1649 }
1650
John Stiles1cf2c8d2020-08-13 22:58:04 -04001651 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001652 // use OpVectorShuffle to mix and match the vector components. We effectively create
1653 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001654 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001655 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001656 // float3L = ...;
1657 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001658 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001659 // 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 -07001660 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1661 // (3, 1, 4).
1662 SpvId base = fGen.nextId();
1663 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1664 SpvId shuffle = fGen.nextId();
1665 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1666 fGen.writeWord(fGen.getType(fBaseType), out);
1667 fGen.writeWord(shuffle, out);
1668 fGen.writeWord(base, out);
1669 fGen.writeWord(value, out);
1670 for (int i = 0; i < fBaseType.columns(); i++) {
1671 // current offset into the virtual vector, defaults to pulling the unmodified
1672 // value from the left side
1673 int offset = i;
1674 // check to see if we are writing this component
1675 for (size_t j = 0; j < fComponents.size(); j++) {
1676 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001677 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001678 // the correct component of the right side instead of preserving the
1679 // value from the left
1680 offset = (int) (j + fBaseType.columns());
1681 break;
1682 }
1683 }
1684 fGen.writeWord(offset, out);
1685 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001686 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001687 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1688 }
1689
1690private:
1691 SPIRVCodeGenerator& fGen;
1692 const SpvId fVecPointer;
1693 const std::vector<int>& fComponents;
1694 const Type& fBaseType;
1695 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001696 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001697};
1698
Greg Daniel64773e62016-11-22 09:44:03 -05001699std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001700 OutputStream& out) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001701 Precision precision = expr.fType.highPrecision() ? Precision::kHigh : Precision::kLow;
Ethan Nicholase6592142020-09-08 10:22:09 -04001702 switch (expr.kind()) {
1703 case Expression::Kind::kVariableReference: {
Ethan Nicholas5226b772018-05-03 16:20:41 -04001704 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07001705 const Variable& var = ((VariableReference&) expr).fVariable;
Ethan Nicholas5226b772018-05-03 16:20:41 -04001706 if (var.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001707 type = this->getType(Type("sk_in", Type::TypeKind::kArray,
1708 var.fType.componentType(), fSkInCount));
Ethan Nicholas5226b772018-05-03 16:20:41 -04001709 } else {
1710 type = this->getType(expr.fType);
1711 }
ethannicholasd598f792016-07-25 10:08:54 -07001712 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001713 SkASSERT(entry != fVariableMap.end());
Ethan Nicholas5226b772018-05-03 16:20:41 -04001714 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(*this,
1715 entry->second,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001716 type,
1717 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001718 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001719 case Expression::Kind::kIndex: // fall through
1720 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001721 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1722 SpvId member = this->nextId();
1723 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001724 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001725 this->writeWord(member, out);
1726 for (SpvId idx : chain) {
1727 this->writeWord(idx, out);
1728 }
1729 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -04001730 *this,
1731 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001732 this->getType(expr.fType),
1733 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001734 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001735 case Expression::Kind::kSwizzle: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001736 Swizzle& swizzle = (Swizzle&) expr;
1737 size_t count = swizzle.fComponents.size();
1738 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001739 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001740 if (count == 1) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001741 IntLiteral index(fContext, -1, swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001742 SpvId member = this->nextId();
1743 this->writeInstruction(SpvOpAccessChain,
Greg Daniel64773e62016-11-22 09:44:03 -05001744 this->getPointerType(swizzle.fType,
1745 get_storage_class(*swizzle.fBase)),
1746 member,
1747 base,
1748 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001749 out);
1750 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1751 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001752 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001753 this->getType(expr.fType),
1754 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001755 } else {
1756 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
Greg Daniel64773e62016-11-22 09:44:03 -05001757 *this,
1758 base,
1759 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001760 swizzle.fBase->fType,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001761 expr.fType,
1762 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001763 }
1764 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001765 case Expression::Kind::kTernary: {
Ethan Nicholasa583b812018-01-18 13:32:11 -05001766 TernaryExpression& t = (TernaryExpression&) expr;
1767 SpvId test = this->writeExpression(*t.fTest, out);
1768 SpvId end = this->nextId();
1769 SpvId ifTrueLabel = this->nextId();
1770 SpvId ifFalseLabel = this->nextId();
1771 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1772 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1773 this->writeLabel(ifTrueLabel, out);
1774 SpvId ifTrue = this->getLValue(*t.fIfTrue, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001775 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001776 this->writeInstruction(SpvOpBranch, end, out);
1777 ifTrueLabel = fCurrentBlock;
1778 SpvId ifFalse = this->getLValue(*t.fIfFalse, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001779 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001780 ifFalseLabel = fCurrentBlock;
1781 this->writeInstruction(SpvOpBranch, end, out);
1782 SpvId result = this->nextId();
1783 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1784 ifTrueLabel, ifFalse, ifFalseLabel, out);
1785 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1786 *this,
1787 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001788 this->getType(expr.fType),
1789 precision));
Ethan Nicholasa583b812018-01-18 13:32:11 -05001790 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001791 default:
1792 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001793 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001794 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1795 // caught by IRGenerator
1796 SpvId result = this->nextId();
1797 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001798 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1799 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001800 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1801 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1802 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001803 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001804 this->getType(expr.fType),
1805 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001806 }
1807}
1808
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001809SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001810 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001811 auto entry = fVariableMap.find(&ref.fVariable);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001812 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001813 SpvId var = entry->second;
ethannicholasd598f792016-07-25 10:08:54 -07001814 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001815 this->writePrecisionModifier(ref.fVariable.fType, result);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001816 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
Greg Daniela85e4bf2020-06-17 16:32:45 -04001817 (fProgram.fSettings.fFlipY || fProgram.fSettings.fInverseW)) {
1818 // The x component never changes, so just grab it
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001819 SpvId xId = this->nextId();
1820 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1821 result, 0, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001822
1823 // Calculate the y component which may need to be flipped
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001824 SpvId rawYId = this->nextId();
1825 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1826 result, 1, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001827 SpvId flippedYId = 0;
1828 if (fProgram.fSettings.fFlipY) {
1829 // need to remap to a top-left coordinate system
1830 if (fRTHeightStructId == (SpvId)-1) {
1831 // height variable hasn't been written yet
1832 std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors));
1833 SkASSERT(fRTHeightFieldIndex == (SpvId)-1);
1834 std::vector<Type::Field> fields;
1835 SkASSERT(fProgram.fSettings.fRTHeightOffset >= 0);
1836 fields.emplace_back(
1837 Modifiers(Layout(0, -1, fProgram.fSettings.fRTHeightOffset, -1, -1, -1, -1,
1838 -1, Layout::Format::kUnspecified,
1839 Layout::kUnspecified_Primitive, 1, -1, "", "",
1840 Layout::kNo_Key, Layout::CType::kDefault),
1841 0),
1842 SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1843 StringFragment name("sksl_synthetic_uniforms");
1844 Type intfStruct(-1, name, fields);
1845
1846 int binding = fProgram.fSettings.fRTHeightBinding;
1847 int set = fProgram.fSettings.fRTHeightSet;
1848 SkASSERT(binding != -1 && set != -1);
1849
1850 Layout layout(0, -1, -1, binding, -1, set, -1, -1, Layout::Format::kUnspecified,
1851 Layout::kUnspecified_Primitive, -1, -1, "", "", Layout::kNo_Key,
1852 Layout::CType::kDefault);
John Stiles3ae071e2020-08-05 15:29:29 -04001853 const Variable* intfVar = fSynthetics.takeOwnershipOfSymbol(
1854 std::make_unique<Variable>(/*offset=*/-1,
1855 Modifiers(layout, Modifiers::kUniform_Flag),
1856 name,
1857 intfStruct,
1858 Variable::kGlobal_Storage));
Greg Daniela85e4bf2020-06-17 16:32:45 -04001859 InterfaceBlock intf(-1, intfVar, name, String(""),
1860 std::vector<std::unique_ptr<Expression>>(), st);
Stephen White88574972020-06-23 19:09:29 -04001861
1862 fRTHeightStructId = this->writeInterfaceBlock(intf, false);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001863 fRTHeightFieldIndex = 0;
1864 }
1865 SkASSERT(fRTHeightFieldIndex != (SpvId)-1);
1866
1867 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1868 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1869 SpvId heightPtr = this->nextId();
1870 this->writeOpCode(SpvOpAccessChain, 5, out);
1871 this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform),
1872 out);
1873 this->writeWord(heightPtr, out);
1874 this->writeWord(fRTHeightStructId, out);
1875 this->writeWord(fieldIndexId, out);
1876 SpvId heightRead = this->nextId();
1877 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1878 heightPtr, out);
1879
1880 flippedYId = this->nextId();
1881 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
1882 heightRead, rawYId, out);
1883 }
1884
1885 // The z component will always be zero so we just get an id to the 0 literal
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001886 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001887 SpvId zeroId = writeFloatLiteral(zero);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001888
1889 // Calculate the w component which may need to be inverted
1890 SpvId rawWId = this->nextId();
1891 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawWId,
Ethan Nicholas20798e52018-12-04 12:30:50 -05001892 result, 3, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001893 SpvId invWId = 0;
1894 if (fProgram.fSettings.fInverseW) {
1895 // We need to invert w
1896 FloatLiteral one(fContext, -1, 1.0);
1897 SpvId oneId = writeFloatLiteral(one);
1898 invWId = this->nextId();
1899 this->writeInstruction(SpvOpFDiv, this->getType(*fContext.fFloat_Type), invWId, oneId,
1900 rawWId, out);
1901 }
1902
1903 // Fill in the new fragcoord with the components from above
1904 SpvId adjusted = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001905 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001906 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001907 this->writeWord(adjusted, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001908 this->writeWord(xId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001909 if (fProgram.fSettings.fFlipY) {
1910 this->writeWord(flippedYId, out);
1911 } else {
1912 this->writeWord(rawYId, out);
1913 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001914 this->writeWord(zeroId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001915 if (fProgram.fSettings.fInverseW) {
1916 this->writeWord(invWId, out);
1917 } else {
1918 this->writeWord(rawWId, out);
1919 }
1920
1921 return adjusted;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001922 }
Chris Daltonb91c4662018-08-01 10:46:22 -06001923 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
1924 !fProgram.fSettings.fFlipY) {
1925 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1926 // the default convention of "counter-clockwise face is front".
1927 SpvId inverse = this->nextId();
1928 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1929 result, out);
1930 return inverse;
1931 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001932 return result;
1933}
1934
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001935SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001936 if (expr.fBase->fType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001937 SpvId base = this->writeExpression(*expr.fBase, out);
1938 SpvId index = this->writeExpression(*expr.fIndex, out);
1939 SpvId result = this->nextId();
1940 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.fType), result, base,
1941 index, out);
1942 return result;
1943 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001944 return getLValue(expr, out)->load(out);
1945}
1946
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001947SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001948 return getLValue(f, out)->load(out);
1949}
1950
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001951SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001952 SpvId base = this->writeExpression(*swizzle.fBase, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001953 SpvId result = this->nextId();
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001954 size_t count = swizzle.fComponents.size();
ethannicholasb3058bd2016-07-01 08:22:01 -07001955 if (count == 1) {
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001956 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
1957 swizzle.fComponents[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001958 } else {
1959 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001960 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001961 this->writeWord(result, out);
1962 this->writeWord(base, out);
Ethan Nicholase455f652019-09-13 12:52:55 -04001963 SpvId other = base;
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001964 for (int c : swizzle.fComponents) {
Ethan Nicholase455f652019-09-13 12:52:55 -04001965 if (c < 0) {
1966 if (!fConstantZeroOneVector) {
1967 FloatLiteral zero(fContext, -1, 0);
1968 SpvId zeroId = this->writeFloatLiteral(zero);
1969 FloatLiteral one(fContext, -1, 1);
1970 SpvId oneId = this->writeFloatLiteral(one);
1971 SpvId type = this->getType(*fContext.fFloat2_Type);
1972 fConstantZeroOneVector = this->nextId();
1973 this->writeOpCode(SpvOpConstantComposite, 5, fConstantBuffer);
1974 this->writeWord(type, fConstantBuffer);
1975 this->writeWord(fConstantZeroOneVector, fConstantBuffer);
1976 this->writeWord(zeroId, fConstantBuffer);
1977 this->writeWord(oneId, fConstantBuffer);
1978 }
1979 other = fConstantZeroOneVector;
1980 break;
Ethan Nicholasac285b12019-02-12 16:05:18 -05001981 }
Ethan Nicholasac285b12019-02-12 16:05:18 -05001982 }
1983 this->writeWord(other, out);
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001984 for (int component : swizzle.fComponents) {
Ethan Nicholasac285b12019-02-12 16:05:18 -05001985 if (component == SKSL_SWIZZLE_0) {
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001986 this->writeWord(swizzle.fBase->fType.columns(), out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001987 } else if (component == SKSL_SWIZZLE_1) {
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04001988 this->writeWord(swizzle.fBase->fType.columns() + 1, out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001989 } else {
1990 this->writeWord(component, out);
1991 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001992 }
1993 }
1994 return result;
1995}
1996
Greg Daniel64773e62016-11-22 09:44:03 -05001997SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1998 const Type& operandType, SpvId lhs,
1999 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002000 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002001 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002002 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002003 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002004 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002005 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002006 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002007 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002008 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002009 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002010 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07002011 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002012#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002013 ABORT("invalid operandType: %s", operandType.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002014#endif
ethannicholasb3058bd2016-07-01 08:22:01 -07002015 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04002016 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002017 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
2018 fDecorationBuffer);
2019 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002020 return result;
2021}
2022
Ethan Nicholas48e24052018-03-14 13:51:39 -04002023SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
2024 OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002025 if (operandType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002026 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04002027 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002028 return result;
2029 }
2030 return id;
2031}
2032
Ethan Nicholas68990be2017-07-13 09:36:52 -04002033SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
2034 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002035 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04002036 OutputStream& out) {
2037 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
Ethan Nicholase6592142020-09-08 10:22:09 -04002038 SkASSERT(operandType.typeKind() == Type::TypeKind::kMatrix);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002039 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2040 operandType.rows(),
2041 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04002042 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002043 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04002044 1));
2045 SpvId boolType = this->getType(*fContext.fBool_Type);
2046 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04002047 for (int i = 0; i < operandType.columns(); i++) {
2048 SpvId columnL = this->nextId();
2049 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2050 SpvId columnR = this->nextId();
2051 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002052 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002053 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
2054 SpvId merge = this->nextId();
2055 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002056 if (result != 0) {
2057 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002058 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002059 result = next;
2060 }
2061 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002062 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04002063 }
2064 }
2065 return result;
2066}
2067
Ethan Nicholas0df21132018-07-10 09:37:51 -04002068SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
2069 SpvId rhs, SpvOp_ floatOperator,
2070 SpvOp_ intOperator,
2071 OutputStream& out) {
2072 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
Ethan Nicholase6592142020-09-08 10:22:09 -04002073 SkASSERT(operandType.typeKind() == Type::TypeKind::kMatrix);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002074 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2075 operandType.rows(),
2076 1));
2077 SpvId columns[4];
2078 for (int i = 0; i < operandType.columns(); i++) {
2079 SpvId columnL = this->nextId();
2080 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2081 SpvId columnR = this->nextId();
2082 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2083 columns[i] = this->nextId();
2084 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2085 }
2086 SpvId result = this->nextId();
2087 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2088 this->writeWord(this->getType(operandType), out);
2089 this->writeWord(result, out);
2090 for (int i = 0; i < operandType.columns(); i++) {
2091 this->writeWord(columns[i], out);
2092 }
2093 return result;
2094}
2095
Ethan Nicholas49465b42019-04-17 12:22:21 -04002096std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2097 if (type.isInteger()) {
2098 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002099 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002100 else if (type.isFloat()) {
2101 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002102 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002103 ABORT("math is unsupported on type '%s'", type.name().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002104 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002105}
2106
2107SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Token::Kind op,
2108 const Type& rightType, SpvId rhs,
2109 const Type& resultType, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002110 Type tmp("<invalid>");
Ethan Nicholas48e24052018-03-14 13:51:39 -04002111 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002112 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002113 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2114 // handling in SPIR-V
Ethan Nicholas49465b42019-04-17 12:22:21 -04002115 if (this->getActualType(leftType) != this->getActualType(rightType)) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002116 if (leftType.typeKind() == Type::TypeKind::kVector && rightType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002117 if (op == Token::Kind::TK_SLASH) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002118 SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
2119 SpvId inverse = this->nextId();
2120 this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
2121 rhs = inverse;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002122 op = Token::Kind::TK_STAR;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002123 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002124 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002125 SpvId result = this->nextId();
2126 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2127 result, lhs, rhs, out);
2128 return result;
2129 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002130 // promote number to vector
2131 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002132 const Type& vecType = leftType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002133 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2134 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002135 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002136 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002137 this->writeWord(rhs, out);
2138 }
2139 rhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002140 operandType = &leftType;
Ethan Nicholase6592142020-09-08 10:22:09 -04002141 } else if (rightType.typeKind() == Type::TypeKind::kVector && leftType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002142 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002143 SpvId result = this->nextId();
2144 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2145 result, rhs, lhs, out);
2146 return result;
2147 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002148 // promote number to vector
2149 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002150 const Type& vecType = rightType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002151 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2152 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002153 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002154 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002155 this->writeWord(lhs, out);
2156 }
2157 lhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002158 operandType = &rightType;
Ethan Nicholase6592142020-09-08 10:22:09 -04002159 } else if (leftType.typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002160 SpvOp_ spvop;
Ethan Nicholase6592142020-09-08 10:22:09 -04002161 if (rightType.typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002162 spvop = SpvOpMatrixTimesMatrix;
Ethan Nicholase6592142020-09-08 10:22:09 -04002163 } else if (rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002164 spvop = SpvOpMatrixTimesVector;
ethannicholasb3058bd2016-07-01 08:22:01 -07002165 } else {
Ethan Nicholase6592142020-09-08 10:22:09 -04002166 SkASSERT(rightType.typeKind() == Type::TypeKind::kScalar);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002167 spvop = SpvOpMatrixTimesScalar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002168 }
2169 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002170 this->writeInstruction(spvop, this->getType(resultType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002171 return result;
Ethan Nicholase6592142020-09-08 10:22:09 -04002172 } else if (rightType.typeKind() == Type::TypeKind::kMatrix) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002173 SpvId result = this->nextId();
Ethan Nicholase6592142020-09-08 10:22:09 -04002174 if (leftType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002175 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(resultType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002176 lhs, rhs, out);
2177 } else {
Ethan Nicholase6592142020-09-08 10:22:09 -04002178 SkASSERT(leftType.typeKind() == Type::TypeKind::kScalar);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002179 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(resultType), result,
2180 rhs, lhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002181 }
2182 return result;
2183 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002184 SkASSERT(false);
2185 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002186 }
2187 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002188 tmp = this->getActualType(leftType);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002189 operandType = &tmp;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002190 SkASSERT(*operandType == this->getActualType(rightType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002191 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002192 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002193 case Token::Kind::TK_EQEQ: {
Ethan Nicholase6592142020-09-08 10:22:09 -04002194 if (operandType->typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002195 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002196 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002197 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002198 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002199 const Type* tmpType;
Ethan Nicholase6592142020-09-08 10:22:09 -04002200 if (operandType->typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002201 tmpType = &fContext.fBool_Type->toCompound(fContext,
2202 operandType->columns(),
2203 operandType->rows());
2204 } else {
2205 tmpType = &resultType;
2206 }
2207 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002208 SpvOpFOrdEqual, SpvOpIEqual,
2209 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002210 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002211 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002212 case Token::Kind::TK_NEQ:
Ethan Nicholase6592142020-09-08 10:22:09 -04002213 if (operandType->typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002214 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002215 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002216 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002217 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002218 const Type* tmpType;
Ethan Nicholase6592142020-09-08 10:22:09 -04002219 if (operandType->typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002220 tmpType = &fContext.fBool_Type->toCompound(fContext,
2221 operandType->columns(),
2222 operandType->rows());
2223 } else {
2224 tmpType = &resultType;
2225 }
2226 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002227 SpvOpFOrdNotEqual, SpvOpINotEqual,
2228 SpvOpINotEqual, SpvOpLogicalNotEqual,
2229 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002230 *operandType, SpvOpAny, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002231 case Token::Kind::TK_GT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002232 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002233 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2234 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002235 SpvOpUGreaterThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002236 case Token::Kind::TK_LT:
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, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002239 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002240 case Token::Kind::TK_GTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002241 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002242 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2243 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002244 SpvOpUGreaterThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002245 case Token::Kind::TK_LTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002246 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002247 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2248 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002249 SpvOpULessThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002250 case Token::Kind::TK_PLUS:
Ethan Nicholase6592142020-09-08 10:22:09 -04002251 if (leftType.typeKind() == Type::TypeKind::kMatrix &&
2252 rightType.typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002253 SkASSERT(leftType == rightType);
2254 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002255 SpvOpFAdd, SpvOpIAdd, out);
2256 }
Greg Daniel64773e62016-11-22 09:44:03 -05002257 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002258 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002259 case Token::Kind::TK_MINUS:
Ethan Nicholase6592142020-09-08 10:22:09 -04002260 if (leftType.typeKind() == Type::TypeKind::kMatrix &&
2261 rightType.typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002262 SkASSERT(leftType == rightType);
2263 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002264 SpvOpFSub, SpvOpISub, out);
2265 }
Greg Daniel64773e62016-11-22 09:44:03 -05002266 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002267 SpvOpISub, SpvOpISub, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002268 case Token::Kind::TK_STAR:
Ethan Nicholase6592142020-09-08 10:22:09 -04002269 if (leftType.typeKind() == Type::TypeKind::kMatrix &&
2270 rightType.typeKind() == Type::TypeKind::kMatrix) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002271 // matrix multiply
2272 SpvId result = this->nextId();
2273 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2274 lhs, rhs, out);
2275 return result;
2276 }
Greg Daniel64773e62016-11-22 09:44:03 -05002277 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002278 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002279 case Token::Kind::TK_SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002280 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002281 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002282 case Token::Kind::TK_PERCENT:
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002283 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2284 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002285 case Token::Kind::TK_SHL:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002286 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2287 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2288 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002289 case Token::Kind::TK_SHR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002290 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2291 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2292 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002293 case Token::Kind::TK_BITWISEAND:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002294 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2295 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002296 case Token::Kind::TK_BITWISEOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002297 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2298 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002299 case Token::Kind::TK_BITWISEXOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002300 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2301 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002302 case Token::Kind::TK_COMMA:
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04002303 return rhs;
ethannicholasb3058bd2016-07-01 08:22:01 -07002304 default:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002305 SkASSERT(false);
2306 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002307 }
2308}
2309
Ethan Nicholas49465b42019-04-17 12:22:21 -04002310SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
2311 // handle cases where we don't necessarily evaluate both LHS and RHS
2312 switch (b.fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002313 case Token::Kind::TK_EQ: {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002314 SpvId rhs = this->writeExpression(*b.fRight, out);
2315 this->getLValue(*b.fLeft, out)->store(rhs, out);
2316 return rhs;
2317 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002318 case Token::Kind::TK_LOGICALAND:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002319 return this->writeLogicalAnd(b, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002320 case Token::Kind::TK_LOGICALOR:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002321 return this->writeLogicalOr(b, out);
2322 default:
2323 break;
2324 }
2325
2326 std::unique_ptr<LValue> lvalue;
2327 SpvId lhs;
2328 if (is_assignment(b.fOperator)) {
2329 lvalue = this->getLValue(*b.fLeft, out);
2330 lhs = lvalue->load(out);
2331 } else {
2332 lvalue = nullptr;
2333 lhs = this->writeExpression(*b.fLeft, out);
2334 }
2335 SpvId rhs = this->writeExpression(*b.fRight, out);
2336 SpvId result = this->writeBinaryExpression(b.fLeft->fType, lhs, remove_assignment(b.fOperator),
2337 b.fRight->fType, rhs, b.fType, out);
2338 if (lvalue) {
2339 lvalue->store(result, out);
2340 }
2341 return result;
2342}
2343
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002344SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002345 SkASSERT(a.fOperator == Token::Kind::TK_LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002346 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002347 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2348 SpvId lhs = this->writeExpression(*a.fLeft, out);
2349 SpvId rhsLabel = this->nextId();
2350 SpvId end = this->nextId();
2351 SpvId lhsBlock = fCurrentBlock;
2352 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2353 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2354 this->writeLabel(rhsLabel, out);
2355 SpvId rhs = this->writeExpression(*a.fRight, out);
2356 SpvId rhsBlock = fCurrentBlock;
2357 this->writeInstruction(SpvOpBranch, end, out);
2358 this->writeLabel(end, out);
2359 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002360 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002361 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002362 return result;
2363}
2364
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002365SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002366 SkASSERT(o.fOperator == Token::Kind::TK_LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002367 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002368 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2369 SpvId lhs = this->writeExpression(*o.fLeft, out);
2370 SpvId rhsLabel = this->nextId();
2371 SpvId end = this->nextId();
2372 SpvId lhsBlock = fCurrentBlock;
2373 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2374 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2375 this->writeLabel(rhsLabel, out);
2376 SpvId rhs = this->writeExpression(*o.fRight, out);
2377 SpvId rhsBlock = fCurrentBlock;
2378 this->writeInstruction(SpvOpBranch, end, out);
2379 this->writeLabel(end, out);
2380 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002381 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002382 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002383 return result;
2384}
2385
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002386SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002387 SpvId test = this->writeExpression(*t.fTest, out);
Brian Osmanb6b95732020-06-30 11:44:27 -04002388 if (t.fIfTrue->fType.columns() == 1 &&
2389 t.fIfTrue->isCompileTimeConstant() &&
2390 t.fIfFalse->isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002391 // both true and false are constants, can just use OpSelect
2392 SpvId result = this->nextId();
2393 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2394 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
Greg Daniel64773e62016-11-22 09:44:03 -05002395 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002396 out);
2397 return result;
2398 }
Greg Daniel64773e62016-11-22 09:44:03 -05002399 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002400 // Adreno. Switched to storing the result in a temp variable as glslang does.
2401 SpvId var = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002402 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002403 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002404 SpvId trueLabel = this->nextId();
2405 SpvId falseLabel = this->nextId();
2406 SpvId end = this->nextId();
2407 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2408 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2409 this->writeLabel(trueLabel, out);
2410 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2411 this->writeInstruction(SpvOpBranch, end, out);
2412 this->writeLabel(falseLabel, out);
2413 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2414 this->writeInstruction(SpvOpBranch, end, out);
2415 this->writeLabel(end, out);
2416 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002417 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002418 this->writePrecisionModifier(t.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002419 return result;
2420}
2421
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002422SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002423 if (p.fOperator == Token::Kind::TK_MINUS) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002424 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002425 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002426 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002427 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002428 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002429 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002430 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2431 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002432#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002433 ABORT("unsupported prefix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002434#endif
Brian Salomon23356442018-11-30 15:33:19 -05002435 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002436 this->writePrecisionModifier(p.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002437 return result;
2438 }
2439 switch (p.fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002440 case Token::Kind::TK_PLUS:
ethannicholasb3058bd2016-07-01 08:22:01 -07002441 return this->writeExpression(*p.fOperand, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002442 case Token::Kind::TK_PLUSPLUS: {
ethannicholasb3058bd2016-07-01 08:22:01 -07002443 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002444 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002445 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2446 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002447 out);
2448 lv->store(result, out);
2449 return result;
2450 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002451 case Token::Kind::TK_MINUSMINUS: {
ethannicholasb3058bd2016-07-01 08:22:01 -07002452 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002453 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002454 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2455 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002456 out);
2457 lv->store(result, out);
2458 return result;
2459 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002460 case Token::Kind::TK_LOGICALNOT: {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002461 SkASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002462 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002463 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002464 this->writeExpression(*p.fOperand, out), out);
2465 return result;
2466 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002467 case Token::Kind::TK_BITWISENOT: {
ethannicholas5961bc92016-10-12 06:39:56 -07002468 SpvId result = this->nextId();
2469 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2470 this->writeExpression(*p.fOperand, out), out);
2471 return result;
2472 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002473 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002474#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002475 ABORT("unsupported prefix expression: %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002476#endif
2477 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002478 }
2479}
2480
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002481SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002482 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2483 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002484 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002485 switch (p.fOperator) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002486 case Token::Kind::TK_PLUSPLUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002487 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002488 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2489 lv->store(temp, out);
2490 return result;
2491 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002492 case Token::Kind::TK_MINUSMINUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002493 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002494 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2495 lv->store(temp, out);
2496 return result;
2497 }
2498 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002499#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002500 ABORT("unsupported postfix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002501#endif
2502 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002503 }
2504}
2505
ethannicholasf789b382016-08-03 12:43:36 -07002506SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002507 if (b.fValue) {
2508 if (fBoolTrue == 0) {
2509 fBoolTrue = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002510 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002511 fConstantBuffer);
2512 }
2513 return fBoolTrue;
2514 } else {
2515 if (fBoolFalse == 0) {
2516 fBoolFalse = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002517 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002518 fConstantBuffer);
2519 }
2520 return fBoolFalse;
2521 }
2522}
2523
ethannicholasf789b382016-08-03 12:43:36 -07002524SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002525 ConstantType type;
ethannicholasd598f792016-07-25 10:08:54 -07002526 if (i.fType == *fContext.fInt_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002527 type = ConstantType::kInt;
2528 } else if (i.fType == *fContext.fUInt_Type) {
2529 type = ConstantType::kUInt;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002530 } else if (i.fType == *fContext.fShort_Type || i.fType == *fContext.fByte_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002531 type = ConstantType::kShort;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002532 } else if (i.fType == *fContext.fUShort_Type || i.fType == *fContext.fUByte_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002533 type = ConstantType::kUShort;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002534 } else {
2535 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002536 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002537 std::pair<ConstantValue, ConstantType> key(i.fValue, type);
2538 auto entry = fNumberConstants.find(key);
2539 if (entry == fNumberConstants.end()) {
2540 SpvId result = this->nextId();
2541 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
2542 fConstantBuffer);
2543 fNumberConstants[key] = result;
2544 return result;
2545 }
2546 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002547}
2548
ethannicholasf789b382016-08-03 12:43:36 -07002549SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
John Stiles8c578662020-06-01 15:32:47 +00002550 ConstantType type;
2551 if (f.fType == *fContext.fHalf_Type) {
2552 type = ConstantType::kHalf;
ethannicholasb3058bd2016-07-01 08:22:01 -07002553 } else {
John Stiles8c578662020-06-01 15:32:47 +00002554 type = ConstantType::kFloat;
ethannicholasb3058bd2016-07-01 08:22:01 -07002555 }
John Stiles8c578662020-06-01 15:32:47 +00002556 float value = (float) f.fValue;
2557 std::pair<ConstantValue, ConstantType> key(f.fValue, type);
2558 auto entry = fNumberConstants.find(key);
2559 if (entry == fNumberConstants.end()) {
2560 SpvId result = this->nextId();
2561 uint32_t bits;
2562 SkASSERT(sizeof(bits) == sizeof(value));
2563 memcpy(&bits, &value, sizeof(bits));
2564 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
2565 fConstantBuffer);
2566 fNumberConstants[key] = result;
2567 return result;
2568 }
2569 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002570}
2571
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002572SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002573 SpvId result = fFunctionMap[&f];
Greg Daniel64773e62016-11-22 09:44:03 -05002574 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002575 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002576 this->writeInstruction(SpvOpName, result, f.fName, fNameBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002577 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002578 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002579 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002580 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002581 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002582 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2583 }
2584 return result;
2585}
2586
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002587SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2588 fVariableBuffer.reset();
ethannicholasb3058bd2016-07-01 08:22:01 -07002589 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2590 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002591 StringStream bodyBuffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04002592 this->writeBlock((Block&) *f.fBody, bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002593 write_stringstream(fVariableBuffer, out);
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002594 if (f.fDeclaration.fName == "main") {
2595 write_stringstream(fGlobalInitializersBuffer, out);
2596 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002597 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002598 if (fCurrentBlock) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002599 if (f.fDeclaration.fReturnType == *fContext.fVoid_Type) {
2600 this->writeInstruction(SpvOpReturn, out);
2601 } else {
2602 this->writeInstruction(SpvOpUnreachable, out);
2603 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002604 }
2605 this->writeInstruction(SpvOpFunctionEnd, out);
2606 return result;
2607}
2608
2609void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2610 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002611 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002612 fDecorationBuffer);
2613 }
2614 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002615 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002616 fDecorationBuffer);
2617 }
2618 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002619 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002620 fDecorationBuffer);
2621 }
2622 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002623 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002624 fDecorationBuffer);
2625 }
Greg Daniel64773e62016-11-22 09:44:03 -05002626 if (layout.fInputAttachmentIndex >= 0) {
2627 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2628 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002629 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002630 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002631 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002632 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002633 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002634 fDecorationBuffer);
2635 }
2636}
2637
2638void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2639 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002640 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002641 layout.fLocation, fDecorationBuffer);
2642 }
2643 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002644 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002645 layout.fBinding, fDecorationBuffer);
2646 }
2647 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002648 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002649 layout.fIndex, fDecorationBuffer);
2650 }
2651 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002652 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002653 layout.fSet, fDecorationBuffer);
2654 }
Greg Daniel64773e62016-11-22 09:44:03 -05002655 if (layout.fInputAttachmentIndex >= 0) {
2656 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2657 layout.fInputAttachmentIndex, fDecorationBuffer);
2658 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002659 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002660 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002661 layout.fBuiltin, fDecorationBuffer);
2662 }
2663}
2664
Ethan Nicholas81d15112018-07-13 12:48:50 -04002665static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2666 switch (m.fLayout.fPrimitive) {
2667 case Layout::kPoints_Primitive:
2668 *outSkInCount = 1;
2669 break;
2670 case Layout::kLines_Primitive:
2671 *outSkInCount = 2;
2672 break;
2673 case Layout::kLinesAdjacency_Primitive:
2674 *outSkInCount = 4;
2675 break;
2676 case Layout::kTriangles_Primitive:
2677 *outSkInCount = 3;
2678 break;
2679 case Layout::kTrianglesAdjacency_Primitive:
2680 *outSkInCount = 6;
2681 break;
2682 default:
2683 return;
2684 }
2685}
2686
Stephen White88574972020-06-23 19:09:29 -04002687SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf, bool appendRTHeight) {
Ethan Nicholas361941e2017-05-30 15:41:07 -04002688 bool isBuffer = (0 != (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag));
Ethan Nicholas39204fd2017-11-27 13:12:30 -05002689 bool pushConstant = (0 != (intf.fVariable.fModifiers.fLayout.fFlags &
2690 Layout::kPushConstant_Flag));
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002691 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2692 MemoryLayout(MemoryLayout::k430_Standard) :
2693 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002694 SpvId result = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002695 const Type* type = &intf.fVariable.fType;
Stephen White88574972020-06-23 19:09:29 -04002696 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Greg Daniele6ab9982018-08-22 13:56:32 +00002697 SkASSERT(fRTHeightStructId == (SpvId) -1);
2698 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002699 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002700 fRTHeightStructId = result;
2701 fRTHeightFieldIndex = fields.size();
2702 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002703 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002704 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002705 SpvId typeId;
2706 if (intf.fVariable.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2707 for (const auto& e : fProgram) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002708 if (e.kind() == ProgramElement::Kind::kModifiers) {
Ethan Nicholas5226b772018-05-03 16:20:41 -04002709 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholas81d15112018-07-13 12:48:50 -04002710 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002711 }
2712 }
Ethan Nicholase6592142020-09-08 10:22:09 -04002713 typeId = this->getType(Type("sk_in", Type::TypeKind::kArray,
2714 intf.fVariable.fType.componentType(),
2715 fSkInCount),
2716 memoryLayout);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002717 } else {
2718 typeId = this->getType(*type, memoryLayout);
2719 }
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002720 if (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag) {
2721 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002722 } else if (intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
2723 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002724 }
ethannicholasd598f792016-07-25 10:08:54 -07002725 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002726 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002727 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002728 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002729 Layout layout = intf.fVariable.fModifiers.fLayout;
2730 if (intf.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
2731 layout.fSet = 0;
2732 }
2733 this->writeLayout(layout, result);
ethannicholasd598f792016-07-25 10:08:54 -07002734 fVariableMap[&intf.fVariable] = result;
Stephen White88574972020-06-23 19:09:29 -04002735 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002736 delete type;
2737 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002738 return result;
2739}
2740
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002741void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002742 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2743}
2744
2745void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2746 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002747 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2748 }
2749}
2750
Chris Dalton2284aab2019-11-15 11:02:24 -07002751bool is_dead(const Variable& var) {
2752 if (var.fReadCount || var.fWriteCount) {
2753 return false;
2754 }
2755 // not entirely sure what the rules are for when it's safe to elide interface variables, but it
2756 // causes various problems to elide some of them even when dead. But it also causes problems
2757 // *not* to elide sk_SampleMask when it's not being used.
2758 if (!(var.fModifiers.fFlags & (Modifiers::kIn_Flag |
2759 Modifiers::kOut_Flag |
2760 Modifiers::kUniform_Flag |
2761 Modifiers::kBuffer_Flag))) {
2762 return true;
2763 }
2764 return var.fModifiers.fLayout.fBuiltin == SK_SAMPLEMASK_BUILTIN;
2765}
2766
ethannicholas5961bc92016-10-12 06:39:56 -07002767#define BUILTIN_IGNORE 9999
Greg Daniel64773e62016-11-22 09:44:03 -05002768void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002769 OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002770 for (size_t i = 0; i < decl.fVars.size(); i++) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002771 if (decl.fVars[i]->kind() == Statement::Kind::kNop) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002772 continue;
2773 }
2774 const VarDeclaration& varDecl = (VarDeclaration&) *decl.fVars[i];
2775 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002776 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2777 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002778 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Chris Daltonb0fd4b12019-10-29 13:41:22 -06002779 Modifiers::kWriteOnly_Flag |
2780 Modifiers::kCoherent_Flag |
2781 Modifiers::kVolatile_Flag |
2782 Modifiers::kRestrict_Flag)));
ethannicholas5961bc92016-10-12 06:39:56 -07002783 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2784 continue;
2785 }
2786 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2787 kind != Program::kFragment_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002788 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
ethannicholas5961bc92016-10-12 06:39:56 -07002789 continue;
2790 }
Chris Dalton2284aab2019-11-15 11:02:24 -07002791 if (is_dead(*var)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002792 continue;
2793 }
2794 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002795 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002796 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002797 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002798 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002799 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002800 if (var->fType.typeKind() == Type::TypeKind::kSampler ||
2801 var->fType.typeKind() == Type::TypeKind::kSeparateSampler ||
2802 var->fType.typeKind() == Type::TypeKind::kTexture) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002803 storageClass = SpvStorageClassUniformConstant;
2804 } else {
2805 storageClass = SpvStorageClassUniform;
2806 }
2807 } else {
2808 storageClass = SpvStorageClassPrivate;
2809 }
2810 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002811 fVariableMap[var] = id;
Ethan Nicholas5226b772018-05-03 16:20:41 -04002812 SpvId type;
2813 if (var->fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002814 type = this->getPointerType(Type("sk_in", Type::TypeKind::kArray,
Ethan Nicholas5226b772018-05-03 16:20:41 -04002815 var->fType.componentType(), fSkInCount),
2816 storageClass);
2817 } else {
2818 type = this->getPointerType(var->fType, storageClass);
2819 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002820 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002821 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002822 this->writePrecisionModifier(var->fType, id);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002823 if (varDecl.fValue) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002824 SkASSERT(!fCurrentBlock);
ethannicholasf789b382016-08-03 12:43:36 -07002825 fCurrentBlock = -1;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002826 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002827 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002828 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002829 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002830 this->writeLayout(var->fModifiers.fLayout, id);
Ethan Nicholas45b0f152017-07-24 14:36:40 -04002831 if (var->fModifiers.fFlags & Modifiers::kFlat_Flag) {
2832 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2833 }
2834 if (var->fModifiers.fFlags & Modifiers::kNoPerspective_Flag) {
2835 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2836 fDecorationBuffer);
2837 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002838 }
2839}
2840
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002841void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002842 for (const auto& stmt : decl.fVars) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002843 SkASSERT(stmt->kind() == Statement::Kind::kVarDeclaration);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002844 VarDeclaration& varDecl = (VarDeclaration&) *stmt;
2845 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002846 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2847 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002848 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002849 Modifiers::kWriteOnly_Flag |
2850 Modifiers::kCoherent_Flag |
2851 Modifiers::kVolatile_Flag |
2852 Modifiers::kRestrict_Flag)));
ethannicholasb3058bd2016-07-01 08:22:01 -07002853 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002854 fVariableMap[var] = id;
2855 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002856 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002857 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002858 if (varDecl.fValue) {
2859 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002860 this->writeInstruction(SpvOpStore, id, value, out);
2861 }
2862 }
2863}
2864
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002865void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002866 switch (s.kind()) {
2867 case Statement::Kind::kNop:
Ethan Nicholascb670962017-04-20 19:31:52 -04002868 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002869 case Statement::Kind::kBlock:
ethannicholasb3058bd2016-07-01 08:22:01 -07002870 this->writeBlock((Block&) s, out);
2871 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002872 case Statement::Kind::kExpression:
John Stiles26f98502020-08-18 09:30:51 -04002873 this->writeExpression(*s.as<ExpressionStatement>().fExpression, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002874 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002875 case Statement::Kind::kReturn:
John Stiles26f98502020-08-18 09:30:51 -04002876 this->writeReturnStatement(s.as<ReturnStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002877 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002878 case Statement::Kind::kVarDeclarations:
John Stiles26f98502020-08-18 09:30:51 -04002879 this->writeVarDeclarations(*s.as<VarDeclarationsStatement>().fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002880 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002881 case Statement::Kind::kIf:
John Stiles26f98502020-08-18 09:30:51 -04002882 this->writeIfStatement(s.as<IfStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002883 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002884 case Statement::Kind::kFor:
John Stiles26f98502020-08-18 09:30:51 -04002885 this->writeForStatement(s.as<ForStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002886 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002887 case Statement::Kind::kWhile:
John Stiles26f98502020-08-18 09:30:51 -04002888 this->writeWhileStatement(s.as<WhileStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002889 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002890 case Statement::Kind::kDo:
John Stiles26f98502020-08-18 09:30:51 -04002891 this->writeDoStatement(s.as<DoStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002892 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002893 case Statement::Kind::kSwitch:
John Stiles26f98502020-08-18 09:30:51 -04002894 this->writeSwitchStatement(s.as<SwitchStatement>(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002895 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002896 case Statement::Kind::kBreak:
ethannicholasb3058bd2016-07-01 08:22:01 -07002897 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2898 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002899 case Statement::Kind::kContinue:
ethannicholasb3058bd2016-07-01 08:22:01 -07002900 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2901 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002902 case Statement::Kind::kDiscard:
ethannicholasb3058bd2016-07-01 08:22:01 -07002903 this->writeInstruction(SpvOpKill, out);
2904 break;
2905 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002906#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002907 ABORT("unsupported statement: %s", s.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002908#endif
2909 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002910 }
2911}
2912
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002913void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002914 for (size_t i = 0; i < b.fStatements.size(); i++) {
2915 this->writeStatement(*b.fStatements[i], out);
2916 }
2917}
2918
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002919void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002920 SpvId test = this->writeExpression(*stmt.fTest, out);
2921 SpvId ifTrue = this->nextId();
2922 SpvId ifFalse = this->nextId();
2923 if (stmt.fIfFalse) {
2924 SpvId end = this->nextId();
2925 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2926 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2927 this->writeLabel(ifTrue, out);
2928 this->writeStatement(*stmt.fIfTrue, out);
2929 if (fCurrentBlock) {
2930 this->writeInstruction(SpvOpBranch, end, out);
2931 }
2932 this->writeLabel(ifFalse, out);
2933 this->writeStatement(*stmt.fIfFalse, out);
2934 if (fCurrentBlock) {
2935 this->writeInstruction(SpvOpBranch, end, out);
2936 }
2937 this->writeLabel(end, out);
2938 } else {
2939 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2940 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2941 this->writeLabel(ifTrue, out);
2942 this->writeStatement(*stmt.fIfTrue, out);
2943 if (fCurrentBlock) {
2944 this->writeInstruction(SpvOpBranch, ifFalse, out);
2945 }
2946 this->writeLabel(ifFalse, out);
2947 }
2948}
2949
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002950void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002951 if (f.fInitializer) {
2952 this->writeStatement(*f.fInitializer, out);
2953 }
2954 SpvId header = this->nextId();
2955 SpvId start = this->nextId();
2956 SpvId body = this->nextId();
2957 SpvId next = this->nextId();
2958 fContinueTarget.push(next);
2959 SpvId end = this->nextId();
2960 fBreakTarget.push(end);
2961 this->writeInstruction(SpvOpBranch, header, out);
2962 this->writeLabel(header, out);
2963 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002964 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002965 this->writeLabel(start, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002966 if (f.fTest) {
2967 SpvId test = this->writeExpression(*f.fTest, out);
2968 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2969 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002970 this->writeLabel(body, out);
2971 this->writeStatement(*f.fStatement, out);
2972 if (fCurrentBlock) {
2973 this->writeInstruction(SpvOpBranch, next, out);
2974 }
2975 this->writeLabel(next, out);
2976 if (f.fNext) {
2977 this->writeExpression(*f.fNext, out);
2978 }
2979 this->writeInstruction(SpvOpBranch, header, out);
2980 this->writeLabel(end, out);
2981 fBreakTarget.pop();
2982 fContinueTarget.pop();
2983}
2984
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002985void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002986 SpvId header = this->nextId();
2987 SpvId start = this->nextId();
2988 SpvId body = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04002989 SpvId continueTarget = this->nextId();
2990 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002991 SpvId end = this->nextId();
2992 fBreakTarget.push(end);
2993 this->writeInstruction(SpvOpBranch, header, out);
2994 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04002995 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002996 this->writeInstruction(SpvOpBranch, start, out);
2997 this->writeLabel(start, out);
2998 SpvId test = this->writeExpression(*w.fTest, out);
2999 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
3000 this->writeLabel(body, out);
3001 this->writeStatement(*w.fStatement, out);
3002 if (fCurrentBlock) {
Ethan Nicholas0d997662019-04-08 09:46:01 -04003003 this->writeInstruction(SpvOpBranch, continueTarget, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003004 }
Ethan Nicholas0d997662019-04-08 09:46:01 -04003005 this->writeLabel(continueTarget, out);
3006 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003007 this->writeLabel(end, out);
3008 fBreakTarget.pop();
3009 fContinueTarget.pop();
3010}
3011
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003012void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003013 SpvId header = this->nextId();
3014 SpvId start = this->nextId();
3015 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003016 SpvId continueTarget = this->nextId();
3017 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003018 SpvId end = this->nextId();
3019 fBreakTarget.push(end);
3020 this->writeInstruction(SpvOpBranch, header, out);
3021 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003022 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003023 this->writeInstruction(SpvOpBranch, start, out);
3024 this->writeLabel(start, out);
3025 this->writeStatement(*d.fStatement, out);
3026 if (fCurrentBlock) {
3027 this->writeInstruction(SpvOpBranch, next, out);
3028 }
3029 this->writeLabel(next, out);
3030 SpvId test = this->writeExpression(*d.fTest, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003031 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
3032 this->writeLabel(continueTarget, out);
3033 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003034 this->writeLabel(end, out);
3035 fBreakTarget.pop();
3036 fContinueTarget.pop();
3037}
3038
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003039void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
3040 SpvId value = this->writeExpression(*s.fValue, out);
3041 std::vector<SpvId> labels;
3042 SpvId end = this->nextId();
3043 SpvId defaultLabel = end;
3044 fBreakTarget.push(end);
3045 int size = 3;
3046 for (const auto& c : s.fCases) {
3047 SpvId label = this->nextId();
3048 labels.push_back(label);
3049 if (c->fValue) {
3050 size += 2;
3051 } else {
3052 defaultLabel = label;
3053 }
3054 }
3055 labels.push_back(end);
3056 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3057 this->writeOpCode(SpvOpSwitch, size, out);
3058 this->writeWord(value, out);
3059 this->writeWord(defaultLabel, out);
3060 for (size_t i = 0; i < s.fCases.size(); ++i) {
3061 if (!s.fCases[i]->fValue) {
3062 continue;
3063 }
John Stiles81365af2020-08-18 09:24:00 -04003064 this->writeWord(s.fCases[i]->fValue->as<IntLiteral>().fValue, out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003065 this->writeWord(labels[i], out);
3066 }
3067 for (size_t i = 0; i < s.fCases.size(); ++i) {
3068 this->writeLabel(labels[i], out);
3069 for (const auto& stmt : s.fCases[i]->fStatements) {
3070 this->writeStatement(*stmt, out);
3071 }
3072 if (fCurrentBlock) {
3073 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3074 }
3075 }
3076 this->writeLabel(end, out);
3077 fBreakTarget.pop();
3078}
3079
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003080void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003081 if (r.fExpression) {
Greg Daniel64773e62016-11-22 09:44:03 -05003082 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003083 out);
3084 } else {
3085 this->writeInstruction(SpvOpReturn, out);
3086 }
3087}
3088
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003089void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003090 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003091 int invocations = 1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003092 for (const auto& e : fProgram) {
Ethan Nicholase6592142020-09-08 10:22:09 -04003093 if (e.kind() == ProgramElement::Kind::kModifiers) {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003094 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003095 if (m.fFlags & Modifiers::kIn_Flag) {
3096 if (m.fLayout.fInvocations != -1) {
3097 invocations = m.fLayout.fInvocations;
3098 }
3099 SpvId input;
3100 switch (m.fLayout.fPrimitive) {
3101 case Layout::kPoints_Primitive:
3102 input = SpvExecutionModeInputPoints;
3103 break;
3104 case Layout::kLines_Primitive:
3105 input = SpvExecutionModeInputLines;
3106 break;
3107 case Layout::kLinesAdjacency_Primitive:
3108 input = SpvExecutionModeInputLinesAdjacency;
3109 break;
3110 case Layout::kTriangles_Primitive:
3111 input = SpvExecutionModeTriangles;
3112 break;
3113 case Layout::kTrianglesAdjacency_Primitive:
3114 input = SpvExecutionModeInputTrianglesAdjacency;
3115 break;
3116 default:
3117 input = 0;
3118 break;
3119 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003120 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003121 if (input) {
3122 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3123 }
3124 } else if (m.fFlags & Modifiers::kOut_Flag) {
3125 SpvId output;
3126 switch (m.fLayout.fPrimitive) {
3127 case Layout::kPoints_Primitive:
3128 output = SpvExecutionModeOutputPoints;
3129 break;
3130 case Layout::kLineStrip_Primitive:
3131 output = SpvExecutionModeOutputLineStrip;
3132 break;
3133 case Layout::kTriangleStrip_Primitive:
3134 output = SpvExecutionModeOutputTriangleStrip;
3135 break;
3136 default:
3137 output = 0;
3138 break;
3139 }
3140 if (output) {
3141 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3142 }
3143 if (m.fLayout.fMaxVertices != -1) {
3144 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3145 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3146 out);
3147 }
3148 }
3149 }
3150 }
3151 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3152 invocations, out);
3153}
3154
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003155void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003156 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003157 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003158 std::set<SpvId> interfaceVars;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003159 // assign IDs to functions, determine sk_in size
3160 int skInSize = -1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003161 for (const auto& e : program) {
Ethan Nicholase6592142020-09-08 10:22:09 -04003162 switch (e.kind()) {
3163 case ProgramElement::Kind::kFunction: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003164 FunctionDefinition& f = (FunctionDefinition&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003165 fFunctionMap[&f.fDeclaration] = this->nextId();
3166 break;
3167 }
Ethan Nicholase6592142020-09-08 10:22:09 -04003168 case ProgramElement::Kind::kModifiers: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003169 Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003170 if (m.fFlags & Modifiers::kIn_Flag) {
3171 switch (m.fLayout.fPrimitive) {
3172 case Layout::kPoints_Primitive: // break
3173 case Layout::kLines_Primitive:
3174 skInSize = 1;
3175 break;
3176 case Layout::kLinesAdjacency_Primitive: // break
3177 skInSize = 2;
3178 break;
3179 case Layout::kTriangles_Primitive: // break
3180 case Layout::kTrianglesAdjacency_Primitive:
3181 skInSize = 3;
3182 break;
3183 default:
3184 break;
3185 }
3186 }
3187 break;
3188 }
3189 default:
3190 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003191 }
3192 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003193 for (const auto& e : program) {
Ethan Nicholase6592142020-09-08 10:22:09 -04003194 if (e.kind() == ProgramElement::Kind::kInterfaceBlock) {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003195 InterfaceBlock& intf = (InterfaceBlock&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003196 if (SK_IN_BUILTIN == intf.fVariable.fModifiers.fLayout.fBuiltin) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003197 SkASSERT(skInSize != -1);
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003198 intf.fSizes.emplace_back(new IntLiteral(fContext, -1, skInSize));
3199 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003200 SpvId id = this->writeInterfaceBlock(intf);
Ethan Nicholas16c11962018-03-16 12:20:54 -04003201 if (((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
3202 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) &&
Chris Dalton2284aab2019-11-15 11:02:24 -07003203 intf.fVariable.fModifiers.fLayout.fBuiltin == -1 &&
3204 !is_dead(intf.fVariable)) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003205 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003206 }
3207 }
3208 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003209 for (const auto& e : program) {
Ethan Nicholase6592142020-09-08 10:22:09 -04003210 if (e.kind() == ProgramElement::Kind::kVar) {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003211 this->writeGlobalVars(program.fKind, ((VarDeclarations&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003212 }
3213 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003214 for (const auto& e : program) {
Ethan Nicholase6592142020-09-08 10:22:09 -04003215 if (e.kind() == ProgramElement::Kind::kFunction) {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003216 this->writeFunction(((FunctionDefinition&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003217 }
3218 }
ethannicholasd598f792016-07-25 10:08:54 -07003219 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003220 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07003221 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003222 main = entry.first;
3223 }
3224 }
Ethan Nicholas1a668d22019-04-18 10:37:40 -04003225 if (!main) {
3226 fErrors.error(0, "program does not contain a main() function");
3227 return;
3228 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003229 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003230 const Variable* var = entry.first;
Greg Daniel64773e62016-11-22 09:44:03 -05003231 if (var->fStorage == Variable::kGlobal_Storage &&
Ethan Nicholas16c11962018-03-16 12:20:54 -04003232 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
Chris Dalton2284aab2019-11-15 11:02:24 -07003233 (var->fModifiers.fFlags & Modifiers::kOut_Flag)) && !is_dead(*var)) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003234 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003235 }
3236 }
3237 this->writeCapabilities(out);
3238 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3239 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003240 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->fName.fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003241 (int32_t) interfaceVars.size(), out);
3242 switch (program.fKind) {
3243 case Program::kVertex_Kind:
3244 this->writeWord(SpvExecutionModelVertex, out);
3245 break;
3246 case Program::kFragment_Kind:
3247 this->writeWord(SpvExecutionModelFragment, out);
3248 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003249 case Program::kGeometry_Kind:
3250 this->writeWord(SpvExecutionModelGeometry, out);
3251 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003252 default:
3253 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003254 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003255 SpvId entryPoint = fFunctionMap[main];
3256 this->writeWord(entryPoint, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003257 this->writeString(main->fName.fChars, main->fName.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003258 for (int var : interfaceVars) {
3259 this->writeWord(var, out);
3260 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003261 if (program.fKind == Program::kGeometry_Kind) {
3262 this->writeGeometryShaderExecutionMode(entryPoint, out);
3263 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003264 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003265 this->writeInstruction(SpvOpExecutionMode,
3266 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003267 SpvExecutionModeOriginUpperLeft,
3268 out);
3269 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003270 for (const auto& e : program) {
Ethan Nicholase6592142020-09-08 10:22:09 -04003271 if (e.kind() == ProgramElement::Kind::kExtension) {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003272 this->writeInstruction(SpvOpSourceExtension, ((Extension&) e).fName.c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003273 }
3274 }
Greg Daniel64773e62016-11-22 09:44:03 -05003275
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003276 write_stringstream(fExtraGlobalsBuffer, out);
3277 write_stringstream(fNameBuffer, out);
3278 write_stringstream(fDecorationBuffer, out);
3279 write_stringstream(fConstantBuffer, out);
3280 write_stringstream(fExternalFunctionsBuffer, out);
3281 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003282}
3283
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003284bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003285 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003286 this->writeWord(SpvMagicNumber, *fOut);
3287 this->writeWord(SpvVersion, *fOut);
3288 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003289 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003290 this->writeInstructions(fProgram, buffer);
3291 this->writeWord(fIdCount, *fOut);
3292 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003293 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003294 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003295}
3296
John Stilesa6841be2020-08-06 14:11:56 -04003297} // namespace SkSL