blob: bcf45f800c24777b48fa293d408ca5b48cf9476f [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);
Brian Osman6ba3be12020-11-13 16:32:52 -050080 fIntrinsicMap[String("step")] = SPECIAL(Step);
81 fIntrinsicMap[String("smoothstep")] = SPECIAL(SmoothStep);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040082 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);
Brian Osman540c13a2020-11-24 16:55:34 -0500117 fIntrinsicMap[String("not")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
118 SpvOpUndef, SpvOpUndef,
119 SpvOpLogicalNot);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400120 fIntrinsicMap[String("equal")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400121 SpvOpFOrdEqual, SpvOpIEqual,
122 SpvOpIEqual, SpvOpLogicalEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400123 fIntrinsicMap[String("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400124 SpvOpFOrdNotEqual, SpvOpINotEqual,
125 SpvOpINotEqual,
126 SpvOpLogicalNotEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400127 fIntrinsicMap[String("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500128 SpvOpFOrdLessThan, SpvOpSLessThan,
129 SpvOpULessThan, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400130 fIntrinsicMap[String("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500131 SpvOpFOrdLessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400132 SpvOpSLessThanEqual,
133 SpvOpULessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400134 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400135 fIntrinsicMap[String("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500136 SpvOpFOrdGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400137 SpvOpSGreaterThan,
138 SpvOpUGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400139 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400140 fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500141 SpvOpFOrdGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400142 SpvOpSGreaterThanEqual,
143 SpvOpUGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400144 SpvOpUndef);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400145 fIntrinsicMap[String("EmitVertex")] = ALL_SPIRV(EmitVertex);
146 fIntrinsicMap[String("EndPrimitive")] = ALL_SPIRV(EndPrimitive);
ethannicholasb3058bd2016-07-01 08:22:01 -0700147// interpolateAt* not yet supported...
148}
149
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400150void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700151 out.write((const char*) &word, sizeof(word));
ethannicholasb3058bd2016-07-01 08:22:01 -0700152}
153
ethannicholasd598f792016-07-25 10:08:54 -0700154static bool is_float(const Context& context, const Type& type) {
Ethan Nicholas0df21132018-07-10 09:37:51 -0400155 if (type.columns() > 1) {
ethannicholasd598f792016-07-25 10:08:54 -0700156 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700157 }
John Stiles8c578662020-06-01 15:32:47 +0000158 return type == *context.fFloat_Type || type == *context.fHalf_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700159}
160
ethannicholasd598f792016-07-25 10:08:54 -0700161static bool is_signed(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500162 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700163 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700164 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400165 return type == *context.fInt_Type || type == *context.fShort_Type ||
166 type == *context.fByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700167}
168
ethannicholasd598f792016-07-25 10:08:54 -0700169static bool is_unsigned(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500170 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700171 return is_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700172 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400173 return type == *context.fUInt_Type || type == *context.fUShort_Type ||
174 type == *context.fUByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700175}
176
ethannicholasd598f792016-07-25 10:08:54 -0700177static bool is_bool(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500178 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700179 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700180 }
ethannicholasd598f792016-07-25 10:08:54 -0700181 return type == *context.fBool_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700182}
183
ethannicholasd598f792016-07-25 10:08:54 -0700184static bool is_out(const Variable& var) {
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400185 return (var.modifiers().fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700186}
187
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400188void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400189 SkASSERT(opCode != SpvOpLoad || &out != &fConstantBuffer);
190 SkASSERT(opCode != SpvOpUndef);
ethannicholasb3058bd2016-07-01 08:22:01 -0700191 switch (opCode) {
192 case SpvOpReturn: // fall through
193 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700194 case SpvOpKill: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700195 case SpvOpBranch: // fall through
196 case SpvOpBranchConditional:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400197 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700198 fCurrentBlock = 0;
199 break;
200 case SpvOpConstant: // fall through
201 case SpvOpConstantTrue: // fall through
202 case SpvOpConstantFalse: // fall through
203 case SpvOpConstantComposite: // fall through
204 case SpvOpTypeVoid: // fall through
205 case SpvOpTypeInt: // fall through
206 case SpvOpTypeFloat: // fall through
207 case SpvOpTypeBool: // fall through
208 case SpvOpTypeVector: // fall through
209 case SpvOpTypeMatrix: // fall through
210 case SpvOpTypeArray: // fall through
211 case SpvOpTypePointer: // fall through
212 case SpvOpTypeFunction: // fall through
213 case SpvOpTypeRuntimeArray: // fall through
214 case SpvOpTypeStruct: // fall through
215 case SpvOpTypeImage: // fall through
216 case SpvOpTypeSampledImage: // fall through
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400217 case SpvOpTypeSampler: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700218 case SpvOpVariable: // fall through
219 case SpvOpFunction: // fall through
220 case SpvOpFunctionParameter: // fall through
221 case SpvOpFunctionEnd: // fall through
222 case SpvOpExecutionMode: // fall through
223 case SpvOpMemoryModel: // fall through
224 case SpvOpCapability: // fall through
225 case SpvOpExtInstImport: // fall through
226 case SpvOpEntryPoint: // fall through
227 case SpvOpSource: // fall through
228 case SpvOpSourceExtension: // fall through
229 case SpvOpName: // fall through
230 case SpvOpMemberName: // fall through
231 case SpvOpDecorate: // fall through
232 case SpvOpMemberDecorate:
233 break;
234 default:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400235 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700236 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700237 this->writeWord((length << 16) | opCode, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700238}
239
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400240void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700241 fCurrentBlock = label;
242 this->writeInstruction(SpvOpLabel, label, out);
243}
244
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400245void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700246 this->writeOpCode(opCode, 1, out);
247}
248
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400249void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700250 this->writeOpCode(opCode, 2, out);
251 this->writeWord(word1, out);
252}
253
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700254void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputStream& out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400255 out.write(string, length);
ethannicholasb3058bd2016-07-01 08:22:01 -0700256 switch (length % 4) {
257 case 1:
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 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500261 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400262 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700263 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500264 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700265 break;
266 default:
267 this->writeWord(0, out);
268 }
269}
270
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700271void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out) {
272 this->writeOpCode(opCode, 1 + (string.fLength + 4) / 4, out);
273 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700274}
275
276
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700277void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400278 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700279 this->writeOpCode(opCode, 2 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700280 this->writeWord(word1, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700281 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700282}
283
Greg Daniel64773e62016-11-22 09:44:03 -0500284void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700285 StringFragment string, OutputStream& out) {
286 this->writeOpCode(opCode, 3 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700287 this->writeWord(word1, out);
288 this->writeWord(word2, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700289 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700290}
291
Greg Daniel64773e62016-11-22 09:44:03 -0500292void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400293 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700294 this->writeOpCode(opCode, 3, out);
295 this->writeWord(word1, out);
296 this->writeWord(word2, out);
297}
298
Greg Daniel64773e62016-11-22 09:44:03 -0500299void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400300 int32_t word3, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700301 this->writeOpCode(opCode, 4, out);
302 this->writeWord(word1, out);
303 this->writeWord(word2, out);
304 this->writeWord(word3, out);
305}
306
Greg Daniel64773e62016-11-22 09:44:03 -0500307void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400308 int32_t word3, int32_t word4, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700309 this->writeOpCode(opCode, 5, out);
310 this->writeWord(word1, out);
311 this->writeWord(word2, out);
312 this->writeWord(word3, out);
313 this->writeWord(word4, out);
314}
315
Greg Daniel64773e62016-11-22 09:44:03 -0500316void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
317 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400318 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700319 this->writeOpCode(opCode, 6, out);
320 this->writeWord(word1, out);
321 this->writeWord(word2, out);
322 this->writeWord(word3, out);
323 this->writeWord(word4, out);
324 this->writeWord(word5, out);
325}
326
Greg Daniel64773e62016-11-22 09:44:03 -0500327void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700328 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400329 int32_t word6, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700330 this->writeOpCode(opCode, 7, out);
331 this->writeWord(word1, out);
332 this->writeWord(word2, out);
333 this->writeWord(word3, out);
334 this->writeWord(word4, out);
335 this->writeWord(word5, out);
336 this->writeWord(word6, out);
337}
338
Greg Daniel64773e62016-11-22 09:44:03 -0500339void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700340 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400341 int32_t word6, int32_t word7, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700342 this->writeOpCode(opCode, 8, out);
343 this->writeWord(word1, out);
344 this->writeWord(word2, out);
345 this->writeWord(word3, out);
346 this->writeWord(word4, out);
347 this->writeWord(word5, out);
348 this->writeWord(word6, out);
349 this->writeWord(word7, out);
350}
351
Greg Daniel64773e62016-11-22 09:44:03 -0500352void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700353 int32_t word3, int32_t word4, int32_t word5,
354 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400355 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700356 this->writeOpCode(opCode, 9, out);
357 this->writeWord(word1, out);
358 this->writeWord(word2, out);
359 this->writeWord(word3, out);
360 this->writeWord(word4, out);
361 this->writeWord(word5, out);
362 this->writeWord(word6, out);
363 this->writeWord(word7, out);
364 this->writeWord(word8, out);
365}
366
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400367void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700368 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
369 if (fCapabilities & bit) {
370 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
371 }
372 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400373 if (fProgram.fKind == Program::kGeometry_Kind) {
374 this->writeInstruction(SpvOpCapability, SpvCapabilityGeometry, out);
375 }
Ethan Nicholas81d15112018-07-13 12:48:50 -0400376 else {
377 this->writeInstruction(SpvOpCapability, SpvCapabilityShader, out);
378 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700379}
380
381SpvId SPIRVCodeGenerator::nextId() {
382 return fIdCount++;
383}
384
Ethan Nicholas19671772016-11-28 16:30:17 -0500385void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
386 SpvId resultId) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400387 this->writeInstruction(SpvOpName, resultId, String(type.name()).c_str(), fNameBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700388 // go ahead and write all of the field types, so we don't inadvertently write them while we're
389 // in the middle of writing the struct instruction
390 std::vector<SpvId> types;
391 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500392 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700393 }
394 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
395 this->writeWord(resultId, fConstantBuffer);
396 for (SpvId id : types) {
397 this->writeWord(id, fConstantBuffer);
398 }
399 size_t offset = 0;
400 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400401 const Type::Field& field = type.fields()[i];
John Stiles21f5f452020-11-30 09:57:59 -0500402 if (!MemoryLayout::LayoutIsSupported(*field.fType)) {
John Stiles0023c0c2020-11-16 13:32:18 -0500403 fErrors.error(type.fOffset, "type '" + field.fType->name() + "' is not permitted here");
404 return;
405 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400406 size_t size = memoryLayout.size(*field.fType);
407 size_t alignment = memoryLayout.alignment(*field.fType);
408 const Layout& fieldLayout = field.fModifiers.fLayout;
Ethan Nicholas19671772016-11-28 16:30:17 -0500409 if (fieldLayout.fOffset >= 0) {
Greg Danieldbd44c72017-01-24 15:12:12 -0500410 if (fieldLayout.fOffset < (int) offset) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700411 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400412 "offset of field '" + field.fName + "' must be at "
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500413 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -0500414 }
415 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700416 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400417 "offset of field '" + field.fName + "' must be a multiple"
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500418 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -0500419 }
420 offset = fieldLayout.fOffset;
421 } else {
422 size_t mod = offset % alignment;
423 if (mod) {
424 offset += alignment - mod;
425 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700426 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400427 this->writeInstruction(SpvOpMemberName, resultId, i, field.fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500428 this->writeLayout(fieldLayout, resultId, i);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400429 if (field.fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -0500430 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700431 (SpvId) offset, fDecorationBuffer);
432 }
John Stiles9aeed132020-11-24 17:36:06 -0500433 if (field.fType->isMatrix()) {
Greg Daniel64773e62016-11-22 09:44:03 -0500434 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -0700435 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500436 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400437 (SpvId) memoryLayout.stride(*field.fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800438 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700439 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400440 if (!field.fType->highPrecision()) {
441 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i,
442 SpvDecorationRelaxedPrecision, fDecorationBuffer);
443 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700444 offset += size;
Ethan Nicholase6592142020-09-08 10:22:09 -0400445 Type::TypeKind kind = field.fType->typeKind();
446 if ((kind == Type::TypeKind::kArray || kind == Type::TypeKind::kStruct) &&
447 offset % alignment != 0) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700448 offset += alignment - offset % alignment;
449 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700450 }
451}
452
Ethan Nicholase2c49992020-10-05 11:49:11 -0400453const Type& SPIRVCodeGenerator::getActualType(const Type& type) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500454 if (type.isFloat()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400455 return *fContext.fFloat_Type;
456 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500457 if (type.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400458 return *fContext.fInt_Type;
459 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500460 if (type.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400461 return *fContext.fUInt_Type;
462 }
John Stiles9aeed132020-11-24 17:36:06 -0500463 if (type.isMatrix() || type.isVector()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400464 if (type.componentType() == *fContext.fHalf_Type) {
465 return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
466 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400467 if (type.componentType() == *fContext.fShort_Type ||
468 type.componentType() == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400469 return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
470 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400471 if (type.componentType() == *fContext.fUShort_Type ||
472 type.componentType() == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400473 return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
474 }
475 }
476 return type;
477}
478
ethannicholasb3058bd2016-07-01 08:22:01 -0700479SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800480 return this->getType(type, fDefaultLayout);
481}
482
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400483SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400484 const Type& type = this->getActualType(rawType);
Jim Van Verthf3ec9832020-10-21 16:09:57 -0400485 String key = type.name();
486 if (type.typeKind() == Type::TypeKind::kStruct || type.typeKind() == Type::TypeKind::kArray) {
487 key += to_string((int)layout.fStd);
488 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800489 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700490 if (entry == fTypeMap.end()) {
491 SpvId result = this->nextId();
Ethan Nicholase6592142020-09-08 10:22:09 -0400492 switch (type.typeKind()) {
493 case Type::TypeKind::kScalar:
John Stiles4a7dc462020-11-25 11:08:08 -0500494 if (type.isBoolean()) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700495 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500496 } else if (type == *fContext.fInt_Type || type == *fContext.fShort_Type ||
497 type == *fContext.fIntLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700498 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500499 } else if (type == *fContext.fUInt_Type || type == *fContext.fUShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700500 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500501 } else if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type ||
502 type == *fContext.fFloatLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700503 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700504 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400505 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700506 }
507 break;
John Stilesfd41d872020-11-25 22:39:45 -0500508 case Type::TypeKind::kEnum:
509 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
510 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400511 case Type::TypeKind::kVector:
Greg Daniel64773e62016-11-22 09:44:03 -0500512 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800513 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700514 type.columns(), fConstantBuffer);
515 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400516 case Type::TypeKind::kMatrix:
Greg Daniel64773e62016-11-22 09:44:03 -0500517 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800518 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700519 type.columns(), fConstantBuffer);
520 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400521 case Type::TypeKind::kStruct:
ethannicholas8ac838d2016-11-22 08:39:36 -0800522 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700523 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400524 case Type::TypeKind::kArray: {
John Stiles21f5f452020-11-30 09:57:59 -0500525 if (!MemoryLayout::LayoutIsSupported(type)) {
526 fErrors.error(type.fOffset, "type '" + type.name() + "' is not permitted here");
527 return this->nextId();
528 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700529 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700530 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500531 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800532 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700533 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500534 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400535 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800536 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700537 } else {
John Stiles5570c512020-11-19 17:58:07 -0500538 // We shouldn't have any runtime-sized arrays right now
539 fErrors.error(type.fOffset, "runtime-sized arrays are not supported in SPIR-V");
Greg Daniel64773e62016-11-22 09:44:03 -0500540 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800541 this->getType(type.componentType(), layout),
542 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400543 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
544 (int32_t) layout.stride(type),
545 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700546 }
547 break;
548 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400549 case Type::TypeKind::kSampler: {
Greg Daniel64773e62016-11-22 09:44:03 -0500550 SpvId image = result;
551 if (SpvDimSubpassData != type.dimensions()) {
Stephen White792e2302019-08-09 13:33:51 -0400552 image = this->getType(type.textureType(), layout);
Greg Daniel64773e62016-11-22 09:44:03 -0500553 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400554 if (SpvDimBuffer == type.dimensions()) {
555 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
556 }
Greg Daniel64773e62016-11-22 09:44:03 -0500557 if (SpvDimSubpassData != type.dimensions()) {
558 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
559 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700560 break;
561 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400562 case Type::TypeKind::kSeparateSampler: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400563 this->writeInstruction(SpvOpTypeSampler, result, fConstantBuffer);
564 break;
565 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400566 case Type::TypeKind::kTexture: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400567 this->writeInstruction(SpvOpTypeImage, result,
568 this->getType(*fContext.fFloat_Type, layout),
Stephen White792e2302019-08-09 13:33:51 -0400569 type.dimensions(), type.isDepth(), type.isArrayed(),
570 type.isMultisampled(), type.isSampled() ? 1 : 2,
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400571 SpvImageFormatUnknown, fConstantBuffer);
572 fImageTypeMap[key] = result;
573 break;
574 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700575 default:
ethannicholasd598f792016-07-25 10:08:54 -0700576 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700577 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
578 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500579#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700580 ABORT("invalid type: %s", type.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500581#endif
ethannicholasb3058bd2016-07-01 08:22:01 -0700582 }
583 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800584 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700585 return result;
586 }
587 return entry->second;
588}
589
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400590SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400591 SkASSERT(type.typeKind() == Type::TypeKind::kSampler);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400592 this->getType(type);
593 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400594 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400595 return fImageTypeMap[key];
596}
597
ethannicholasd598f792016-07-25 10:08:54 -0700598SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400599 String key = to_string(this->getType(function.returnType())) + "(";
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400600 String separator;
Brian Osman5bf3e202020-10-13 10:34:18 -0400601 const std::vector<const Variable*>& parameters = function.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400602 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700603 key += separator;
604 separator = ", ";
Ethan Nicholased84b732020-10-08 11:45:44 -0400605 key += to_string(this->getType(parameters[i]->type()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700606 }
607 key += ")";
608 auto entry = fTypeMap.find(key);
609 if (entry == fTypeMap.end()) {
610 SpvId result = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -0400611 int32_t length = 3 + (int32_t) parameters.size();
612 SpvId returnType = this->getType(function.returnType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700613 std::vector<SpvId> parameterTypes;
Ethan Nicholased84b732020-10-08 11:45:44 -0400614 for (size_t i = 0; i < parameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500615 // glslang seems to treat all function arguments as pointers whether they need to be or
616 // not. I was initially puzzled by this until I ran bizarre failures with certain
617 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700618 // failure case:
619 //
620 // void sphere(float x) {
621 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500622 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700623 // void map() {
624 // sphere(1.0);
625 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500626 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700627 // void main() {
628 // for (int i = 0; i < 1; i++) {
629 // map();
630 // }
631 // }
632 //
Greg Daniel64773e62016-11-22 09:44:03 -0500633 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
634 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700635 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
636 // the spec makes this make sense.
637// if (is_out(function->fParameters[i])) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400638 parameterTypes.push_back(this->getPointerType(parameters[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -0700639 SpvStorageClassFunction));
640// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700641// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700642// }
643 }
644 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
645 this->writeWord(result, fConstantBuffer);
646 this->writeWord(returnType, fConstantBuffer);
647 for (SpvId id : parameterTypes) {
648 this->writeWord(id, fConstantBuffer);
649 }
650 fTypeMap[key] = result;
651 return result;
652 }
653 return entry->second;
654}
655
ethannicholas8ac838d2016-11-22 08:39:36 -0800656SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
657 return this->getPointerType(type, fDefaultLayout, storageClass);
658}
659
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400660SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700661 SpvStorageClass_ storageClass) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400662 const Type& type = this->getActualType(rawType);
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500663 String key = type.displayName() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700664 auto entry = fTypeMap.find(key);
665 if (entry == fTypeMap.end()) {
666 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500667 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700668 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700669 fTypeMap[key] = result;
670 return result;
671 }
672 return entry->second;
673}
674
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400675SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400676 switch (expr.kind()) {
677 case Expression::Kind::kBinary:
John Stiles81365af2020-08-18 09:24:00 -0400678 return this->writeBinaryExpression(expr.as<BinaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400679 case Expression::Kind::kBoolLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400680 return this->writeBoolLiteral(expr.as<BoolLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400681 case Expression::Kind::kConstructor:
John Stiles81365af2020-08-18 09:24:00 -0400682 return this->writeConstructor(expr.as<Constructor>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400683 case Expression::Kind::kIntLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400684 return this->writeIntLiteral(expr.as<IntLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400685 case Expression::Kind::kFieldAccess:
John Stiles81365af2020-08-18 09:24:00 -0400686 return this->writeFieldAccess(expr.as<FieldAccess>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400687 case Expression::Kind::kFloatLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400688 return this->writeFloatLiteral(expr.as<FloatLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400689 case Expression::Kind::kFunctionCall:
John Stiles81365af2020-08-18 09:24:00 -0400690 return this->writeFunctionCall(expr.as<FunctionCall>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400691 case Expression::Kind::kPrefix:
John Stiles81365af2020-08-18 09:24:00 -0400692 return this->writePrefixExpression(expr.as<PrefixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400693 case Expression::Kind::kPostfix:
John Stiles81365af2020-08-18 09:24:00 -0400694 return this->writePostfixExpression(expr.as<PostfixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400695 case Expression::Kind::kSwizzle:
John Stiles81365af2020-08-18 09:24:00 -0400696 return this->writeSwizzle(expr.as<Swizzle>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400697 case Expression::Kind::kVariableReference:
John Stiles81365af2020-08-18 09:24:00 -0400698 return this->writeVariableReference(expr.as<VariableReference>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400699 case Expression::Kind::kTernary:
John Stiles81365af2020-08-18 09:24:00 -0400700 return this->writeTernaryExpression(expr.as<TernaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400701 case Expression::Kind::kIndex:
John Stiles81365af2020-08-18 09:24:00 -0400702 return this->writeIndexExpression(expr.as<IndexExpression>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700703 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500704#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700705 ABORT("unsupported expression: %s", expr.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500706#endif
707 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700708 }
709 return -1;
710}
711
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400712SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400713 const FunctionDeclaration& function = c.function();
John Stiles8e3b6be2020-10-13 11:14:08 -0400714 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400715 auto intrinsic = fIntrinsicMap.find(function.name());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400716 SkASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -0700717 int32_t intrinsicId;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400718 if (arguments.size() > 0) {
719 const Type& type = arguments[0]->type();
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400720 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
721 intrinsicId = std::get<1>(intrinsic->second);
722 } else if (is_signed(fContext, type)) {
723 intrinsicId = std::get<2>(intrinsic->second);
724 } else if (is_unsigned(fContext, type)) {
725 intrinsicId = std::get<3>(intrinsic->second);
726 } else if (is_bool(fContext, type)) {
727 intrinsicId = std::get<4>(intrinsic->second);
728 } else {
729 intrinsicId = std::get<1>(intrinsic->second);
730 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700731 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400732 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700733 }
734 switch (std::get<0>(intrinsic->second)) {
735 case kGLSL_STD_450_IntrinsicKind: {
736 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400737 std::vector<SpvId> argumentIds;
738 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400739 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400740 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400741 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400742 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400743 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700744 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400745 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400746 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700747 this->writeWord(result, out);
748 this->writeWord(fGLSLExtendedInstructions, out);
749 this->writeWord(intrinsicId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400750 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700751 this->writeWord(id, out);
752 }
753 return result;
754 }
755 case kSPIRV_IntrinsicKind: {
Brian Osman46787d52020-11-24 14:18:23 -0500756 // GLSL supports dot(float, float), but SPIR-V does not. Convert it to FMul
John Stiles9aeed132020-11-24 17:36:06 -0500757 if (intrinsicId == SpvOpDot && arguments[0]->type().isScalar()) {
Brian Osman46787d52020-11-24 14:18:23 -0500758 intrinsicId = SpvOpFMul;
759 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700760 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400761 std::vector<SpvId> argumentIds;
762 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400763 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400764 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400765 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400766 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400767 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700768 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400769 if (c.type() != *fContext.fVoid_Type) {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400770 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400771 this->writeWord(this->getType(c.type()), out);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400772 this->writeWord(result, out);
773 } else {
774 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
775 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400776 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700777 this->writeWord(id, out);
778 }
779 return result;
780 }
781 case kSpecial_IntrinsicKind:
782 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
783 default:
784 ABORT("unsupported intrinsic kind");
785 }
786}
787
John Stiles8e3b6be2020-10-13 11:14:08 -0400788std::vector<SpvId> SPIRVCodeGenerator::vectorize(const ExpressionArray& args, OutputStream& out) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500789 int vectorSize = 0;
790 for (const auto& a : args) {
John Stiles9aeed132020-11-24 17:36:06 -0500791 if (a->type().isVector()) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500792 if (vectorSize) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400793 SkASSERT(a->type().columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500794 }
795 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400796 vectorSize = a->type().columns();
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500797 }
798 }
799 }
800 std::vector<SpvId> result;
John Stiles8e3b6be2020-10-13 11:14:08 -0400801 result.reserve(args.size());
Ethan Nicholas30d30222020-09-11 12:27:26 -0400802 for (const auto& arg : args) {
803 const Type& argType = arg->type();
804 SpvId raw = this->writeExpression(*arg, out);
John Stiles9aeed132020-11-24 17:36:06 -0500805 if (vectorSize && argType.isScalar()) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500806 SpvId vector = this->nextId();
807 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400808 this->writeWord(this->getType(argType.toCompound(fContext, vectorSize, 1)), out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500809 this->writeWord(vector, out);
810 for (int i = 0; i < vectorSize; i++) {
811 this->writeWord(raw, out);
812 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400813 this->writePrecisionModifier(argType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500814 result.push_back(vector);
815 } else {
816 result.push_back(raw);
817 }
818 }
819 return result;
820}
821
822void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
823 SpvId signedInst, SpvId unsignedInst,
824 const std::vector<SpvId>& args,
825 OutputStream& out) {
826 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
827 this->writeWord(this->getType(type), out);
828 this->writeWord(id, out);
829 this->writeWord(fGLSLExtendedInstructions, out);
830
831 if (is_float(fContext, type)) {
832 this->writeWord(floatInst, out);
833 } else if (is_signed(fContext, type)) {
834 this->writeWord(signedInst, out);
835 } else if (is_unsigned(fContext, type)) {
836 this->writeWord(unsignedInst, out);
837 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400838 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500839 }
840 for (SpvId a : args) {
841 this->writeWord(a, out);
842 }
843}
844
Greg Daniel64773e62016-11-22 09:44:03 -0500845SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400846 OutputStream& out) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400847 const ExpressionArray& arguments = c.arguments();
ethannicholasb3058bd2016-07-01 08:22:01 -0700848 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400849 const Type& callType = c.type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700850 switch (kind) {
851 case kAtan_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400852 std::vector<SpvId> argumentIds;
853 for (const std::unique_ptr<Expression>& arg : arguments) {
854 argumentIds.push_back(this->writeExpression(*arg, out));
ethannicholasb3058bd2016-07-01 08:22:01 -0700855 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400856 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400857 this->writeWord(this->getType(callType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700858 this->writeWord(result, out);
859 this->writeWord(fGLSLExtendedInstructions, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400860 this->writeWord(argumentIds.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
861 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700862 this->writeWord(id, out);
863 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400864 break;
865 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400866 case kSampledImage_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400867 SkASSERT(arguments.size() == 2);
868 SpvId img = this->writeExpression(*arguments[0], out);
869 SpvId sampler = this->writeExpression(*arguments[1], out);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400870 this->writeInstruction(SpvOpSampledImage,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400871 this->getType(callType),
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400872 result,
873 img,
874 sampler,
875 out);
876 break;
877 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400878 case kSubpassLoad_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400879 SpvId img = this->writeExpression(*arguments[0], out);
John Stiles8e3b6be2020-10-13 11:14:08 -0400880 ExpressionArray args;
John Stilesf4bda742020-10-14 16:57:41 -0400881 args.reserve_back(2);
John Stiles8e3b6be2020-10-13 11:14:08 -0400882 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
883 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
Ethan Nicholas30d30222020-09-11 12:27:26 -0400884 Constructor ctor(-1, fContext.fInt2_Type.get(), std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400885 SpvId coords = this->writeConstantVector(ctor);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400886 if (arguments.size() == 1) {
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400887 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400888 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400889 result,
890 img,
891 coords,
892 out);
893 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400894 SkASSERT(arguments.size() == 2);
895 SpvId sample = this->writeExpression(*arguments[1], out);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400896 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400897 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400898 result,
899 img,
900 coords,
901 SpvImageOperandsSampleMask,
902 sample,
903 out);
904 }
905 break;
906 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700907 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500908 SpvOp_ op = SpvOpImageSampleImplicitLod;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400909 const Type& arg1Type = arguments[1]->type();
910 switch (arguments[0]->type().dimensions()) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500911 case SpvDim1D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400912 if (arg1Type == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500913 op = SpvOpImageSampleProjImplicitLod;
914 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400915 SkASSERT(arg1Type == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500916 }
917 break;
918 case SpvDim2D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400919 if (arg1Type == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500920 op = SpvOpImageSampleProjImplicitLod;
921 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400922 SkASSERT(arg1Type == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500923 }
924 break;
925 case SpvDim3D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400926 if (arg1Type == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500927 op = SpvOpImageSampleProjImplicitLod;
928 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400929 SkASSERT(arg1Type == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500930 }
931 break;
932 case SpvDimCube: // fall through
933 case SpvDimRect: // fall through
934 case SpvDimBuffer: // fall through
935 case SpvDimSubpassData:
936 break;
937 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400938 SpvId type = this->getType(callType);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400939 SpvId sampler = this->writeExpression(*arguments[0], out);
940 SpvId uv = this->writeExpression(*arguments[1], out);
941 if (arguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500942 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700943 SpvImageOperandsBiasMask,
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400944 this->writeExpression(*arguments[2], out),
ethannicholasb3058bd2016-07-01 08:22:01 -0700945 out);
946 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400947 SkASSERT(arguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500948 if (fProgram.fSettings.fSharpenTextures) {
949 FloatLiteral lodBias(fContext, -1, -0.5);
950 this->writeInstruction(op, type, result, sampler, uv,
951 SpvImageOperandsBiasMask,
952 this->writeFloatLiteral(lodBias),
953 out);
954 } else {
955 this->writeInstruction(op, type, result, sampler, uv,
956 out);
957 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700958 }
959 break;
960 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500961 case kMod_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400962 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400963 SkASSERT(args.size() == 2);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400964 const Type& operandType = arguments[0]->type();
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500965 SpvOp_ op;
966 if (is_float(fContext, operandType)) {
967 op = SpvOpFMod;
968 } else if (is_signed(fContext, operandType)) {
969 op = SpvOpSMod;
970 } else if (is_unsigned(fContext, operandType)) {
971 op = SpvOpUMod;
972 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400973 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500974 return 0;
975 }
976 this->writeOpCode(op, 5, out);
977 this->writeWord(this->getType(operandType), out);
978 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500979 this->writeWord(args[0], out);
980 this->writeWord(args[1], out);
981 break;
982 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700983 case kDFdy_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400984 SpvId fn = this->writeExpression(*arguments[0], out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700985 this->writeOpCode(SpvOpDPdy, 4, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400986 this->writeWord(this->getType(callType), out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700987 this->writeWord(result, out);
988 this->writeWord(fn, out);
989 if (fProgram.fSettings.fFlipY) {
990 // Flipping Y also negates the Y derivatives.
991 SpvId flipped = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400992 this->writeInstruction(SpvOpFNegate, this->getType(callType), flipped, result,
993 out);
994 this->writePrecisionModifier(callType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700995 return flipped;
996 }
997 break;
998 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500999 case kClamp_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001000 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001001 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001002 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001003 GLSLstd450UClamp, args, out);
1004 break;
1005 }
1006 case kMax_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001007 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001008 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001009 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMax, GLSLstd450SMax,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001010 GLSLstd450UMax, args, out);
1011 break;
1012 }
1013 case kMin_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001014 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001015 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001016 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMin, GLSLstd450SMin,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001017 GLSLstd450UMin, args, out);
1018 break;
1019 }
1020 case kMix_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001021 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001022 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001023 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMix, SpvOpUndef,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001024 SpvOpUndef, args, out);
1025 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -05001026 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001027 case kSaturate_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001028 SkASSERT(arguments.size() == 1);
John Stiles8e3b6be2020-10-13 11:14:08 -04001029 ExpressionArray finalArgs;
John Stilesf4bda742020-10-14 16:57:41 -04001030 finalArgs.reserve_back(3);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001031 finalArgs.push_back(arguments[0]->clone());
John Stiles8e3b6be2020-10-13 11:14:08 -04001032 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1033 /*value=*/0));
1034 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1035 /*value=*/1));
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001036 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001037 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001038 GLSLstd450UClamp, spvArgs, out);
1039 break;
1040 }
Brian Osman6ba3be12020-11-13 16:32:52 -05001041 case kSmoothStep_SpecialIntrinsic: {
1042 std::vector<SpvId> args = this->vectorize(arguments, out);
1043 SkASSERT(args.size() == 3);
1044 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450SmoothStep, SpvOpUndef,
1045 SpvOpUndef, args, out);
1046 break;
1047 }
1048 case kStep_SpecialIntrinsic: {
1049 std::vector<SpvId> args = this->vectorize(arguments, out);
1050 SkASSERT(args.size() == 2);
1051 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450Step, SpvOpUndef,
1052 SpvOpUndef, args, out);
1053 break;
1054 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001055 }
1056 return result;
1057}
1058
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001059SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001060 const FunctionDeclaration& function = c.function();
John Stiles8e3b6be2020-10-13 11:14:08 -04001061 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001062 const auto& entry = fFunctionMap.find(&function);
ethannicholasb3058bd2016-07-01 08:22:01 -07001063 if (entry == fFunctionMap.end()) {
1064 return this->writeIntrinsicCall(c, out);
1065 }
1066 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001067 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001068 std::vector<SpvId> argumentIds;
1069 for (size_t i = 0; i < arguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001070 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001071 // passed directly
1072 SpvId tmpVar;
1073 // if we need a temporary var to store this argument, this is the value to store in the var
1074 SpvId tmpValueId;
Ethan Nicholased84b732020-10-08 11:45:44 -04001075 if (is_out(*function.parameters()[i])) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001076 std::unique_ptr<LValue> lv = this->getLValue(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001077 SpvId ptr = lv->getPointer();
1078 if (ptr) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001079 argumentIds.push_back(ptr);
ethannicholasb3058bd2016-07-01 08:22:01 -07001080 continue;
1081 } else {
1082 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1083 // copy it into a temp, call the function, read the value out of the temp, and then
1084 // update the lvalue.
1085 tmpValueId = lv->load(out);
1086 tmpVar = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001087 lvalues.push_back(std::make_tuple(tmpVar, &arguments[i]->type(), std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001088 }
1089 } else {
1090 // see getFunctionType for an explanation of why we're always using pointer parameters
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001091 tmpValueId = this->writeExpression(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001092 tmpVar = this->nextId();
1093 }
Greg Daniel64773e62016-11-22 09:44:03 -05001094 this->writeInstruction(SpvOpVariable,
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001095 this->getPointerType(arguments[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001096 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001097 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001098 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001099 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001100 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001101 argumentIds.push_back(tmpVar);
ethannicholasb3058bd2016-07-01 08:22:01 -07001102 }
1103 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001104 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001105 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001106 this->writeWord(result, out);
1107 this->writeWord(entry->second, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001108 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001109 this->writeWord(id, out);
1110 }
1111 // now that the call is complete, we may need to update some lvalues with the new values of out
1112 // arguments
1113 for (const auto& tuple : lvalues) {
1114 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001115 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1116 out);
1117 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001118 std::get<2>(tuple)->store(load, out);
1119 }
1120 return result;
1121}
1122
ethannicholasf789b382016-08-03 12:43:36 -07001123SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001124 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001125 SkASSERT(type.isVector() && c.isCompileTimeConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001126 SpvId result = this->nextId();
1127 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001128 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1129 arguments.push_back(this->writeExpression(*arg, fConstantBuffer));
ethannicholasb3058bd2016-07-01 08:22:01 -07001130 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001131 SpvId typeId = this->getType(type);
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001132 if (c.arguments().size() == 1) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001133 // with a single argument, a vector will have all of its entries equal to the argument
Ethan Nicholas30d30222020-09-11 12:27:26 -04001134 this->writeOpCode(SpvOpConstantComposite, 3 + type.columns(), fConstantBuffer);
1135 this->writeWord(typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001136 this->writeWord(result, fConstantBuffer);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001137 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001138 this->writeWord(arguments[0], fConstantBuffer);
1139 }
1140 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001141 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.arguments().size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001142 fConstantBuffer);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001143 this->writeWord(typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001144 this->writeWord(result, fConstantBuffer);
1145 for (SpvId id : arguments) {
1146 this->writeWord(id, fConstantBuffer);
1147 }
1148 }
1149 return result;
1150}
1151
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001152SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001153 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001154 SkASSERT(c.arguments().size() == 1);
1155 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001156 SkASSERT(constructorType.isFloat());
1157 SkASSERT(argType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001158 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001159 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001160 if (argType.isSigned()) {
1161 this->writeInstruction(SpvOpConvertSToF, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001162 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001163 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001164 SkASSERT(argType.isUnsigned());
1165 this->writeInstruction(SpvOpConvertUToF, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001166 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001167 }
1168 return result;
1169}
1170
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001171SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001172 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001173 SkASSERT(c.arguments().size() == 1);
1174 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001175 SkASSERT(constructorType.isSigned());
1176 SkASSERT(argType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001177 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001178 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001179 if (argType.isFloat()) {
1180 this->writeInstruction(SpvOpConvertFToS, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001181 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001182 }
1183 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001184 SkASSERT(argType.isUnsigned());
1185 this->writeInstruction(SpvOpBitcast, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001186 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001187 }
1188 return result;
1189}
1190
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001191SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001192 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001193 SkASSERT(c.arguments().size() == 1);
1194 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001195 SkASSERT(constructorType.isUnsigned());
1196 SkASSERT(argType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001197 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001198 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001199 if (argType.isFloat()) {
1200 this->writeInstruction(SpvOpConvertFToU, this->getType(constructorType), result, parameter,
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001201 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001202 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001203 SkASSERT(argType.isSigned());
1204 this->writeInstruction(SpvOpBitcast, this->getType(constructorType), result, parameter,
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001205 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001206 }
1207 return result;
1208}
1209
Ethan Nicholas84645e32017-02-09 13:57:14 -05001210void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001211 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001212 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001213 SpvId zeroId = this->writeFloatLiteral(zero);
1214 std::vector<SpvId> columnIds;
1215 for (int column = 0; column < type.columns(); column++) {
1216 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1217 out);
1218 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1219 out);
1220 SpvId columnId = this->nextId();
1221 this->writeWord(columnId, out);
1222 columnIds.push_back(columnId);
1223 for (int row = 0; row < type.columns(); row++) {
1224 this->writeWord(row == column ? diagonal : zeroId, out);
1225 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001226 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001227 }
1228 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1229 out);
1230 this->writeWord(this->getType(type), out);
1231 this->writeWord(id, out);
John Stilesf621e232020-08-25 13:33:02 -04001232 for (SpvId columnId : columnIds) {
1233 this->writeWord(columnId, out);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001234 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001235 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001236}
1237
1238void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001239 const Type& dstType, OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05001240 SkASSERT(srcType.isMatrix());
1241 SkASSERT(dstType.isMatrix());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001242 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001243 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1244 srcType.rows(),
1245 1));
1246 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1247 dstType.rows(),
1248 1));
1249 SpvId zeroId;
1250 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001251 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001252 zeroId = this->writeFloatLiteral(zero);
1253 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001254 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001255 zeroId = this->writeIntLiteral(zero);
1256 } else {
1257 ABORT("unsupported matrix component type");
1258 }
1259 SpvId zeroColumn = 0;
1260 SpvId columns[4];
1261 for (int i = 0; i < dstType.columns(); i++) {
1262 if (i < srcType.columns()) {
1263 // we're still inside the src matrix, copy the column
1264 SpvId srcColumn = this->nextId();
1265 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001266 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001267 SpvId dstColumn;
1268 if (srcType.rows() == dstType.rows()) {
1269 // columns are equal size, don't need to do anything
1270 dstColumn = srcColumn;
1271 }
1272 else if (dstType.rows() > srcType.rows()) {
1273 // dst column is bigger, need to zero-pad it
1274 dstColumn = this->nextId();
1275 int delta = dstType.rows() - srcType.rows();
1276 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1277 this->writeWord(dstColumnType, out);
1278 this->writeWord(dstColumn, out);
1279 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001280 for (int j = 0; j < delta; ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001281 this->writeWord(zeroId, out);
1282 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001283 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001284 }
1285 else {
1286 // dst column is smaller, need to swizzle the src column
1287 dstColumn = this->nextId();
1288 int count = dstType.rows();
1289 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1290 this->writeWord(dstColumnType, out);
1291 this->writeWord(dstColumn, out);
1292 this->writeWord(srcColumn, out);
1293 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001294 for (int j = 0; j < count; j++) {
1295 this->writeWord(j, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001296 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001297 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001298 }
1299 columns[i] = dstColumn;
1300 } else {
1301 // we're past the end of the src matrix, need a vector of zeroes
1302 if (!zeroColumn) {
1303 zeroColumn = this->nextId();
1304 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1305 this->writeWord(dstColumnType, out);
1306 this->writeWord(zeroColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001307 for (int j = 0; j < dstType.rows(); ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001308 this->writeWord(zeroId, out);
1309 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001310 this->writePrecisionModifier(dstType, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001311 }
1312 columns[i] = zeroColumn;
1313 }
1314 }
1315 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1316 this->writeWord(this->getType(dstType), out);
1317 this->writeWord(id, out);
1318 for (int i = 0; i < dstType.columns(); i++) {
1319 this->writeWord(columns[i], out);
1320 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001321 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001322}
1323
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001324void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1325 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001326 std::vector<SpvId>* columnIds,
1327 int* currentCount, int rows, SpvId entry,
1328 OutputStream& out) {
1329 SkASSERT(*currentCount < rows);
1330 ++(*currentCount);
1331 currentColumn->push_back(entry);
1332 if (*currentCount == rows) {
1333 *currentCount = 0;
1334 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1335 this->writeWord(columnType, out);
1336 SpvId columnId = this->nextId();
1337 this->writeWord(columnId, out);
1338 columnIds->push_back(columnId);
1339 for (SpvId id : *currentColumn) {
1340 this->writeWord(id, out);
1341 }
1342 currentColumn->clear();
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001343 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001344 }
1345}
1346
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001347SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001348 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001349 SkASSERT(type.isMatrix());
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001350 SkASSERT(c.arguments().size() > 0);
1351 const Type& arg0Type = c.arguments()[0]->type();
ethannicholasb3058bd2016-07-01 08:22:01 -07001352 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1353 // an instruction
1354 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001355 for (size_t i = 0; i < c.arguments().size(); i++) {
1356 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001357 }
1358 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001359 int rows = type.rows();
1360 int columns = type.columns();
John Stiles9aeed132020-11-24 17:36:06 -05001361 if (arguments.size() == 1 && arg0Type.isScalar()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001362 this->writeUniformScaleMatrix(result, arguments[0], type, out);
John Stiles9aeed132020-11-24 17:36:06 -05001363 } else if (arguments.size() == 1 && arg0Type.isMatrix()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001364 this->writeMatrixCopy(result, arguments[0], arg0Type, type, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001365 } else if (arguments.size() == 1 &&
John Stiles9aeed132020-11-24 17:36:06 -05001366 arg0Type.isVector()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001367 SkASSERT(type.rows() == 2 && type.columns() == 2);
1368 SkASSERT(arg0Type.columns() == 4);
1369 SpvId componentType = this->getType(type.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001370 SpvId v[4];
1371 for (int i = 0; i < 4; ++i) {
1372 v[i] = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001373 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i,
1374 out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001375 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001376 SpvId columnType = this->getType(type.componentType().toCompound(fContext, 2, 1));
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001377 SpvId column1 = this->nextId();
1378 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1379 SpvId column2 = this->nextId();
1380 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001381 this->writeInstruction(SpvOpCompositeConstruct, this->getType(type), result, column1,
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001382 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001383 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001384 SpvId columnType = this->getType(type.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001385 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001386 // ids of vectors and scalars we have written to the current column so far
1387 std::vector<SpvId> currentColumn;
1388 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001389 int currentCount = 0;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001390 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001391 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001392 const Type& argType = c.arguments()[i]->type();
John Stiles9aeed132020-11-24 17:36:06 -05001393 if (currentCount == 0 && argType.isVector() &&
Ethan Nicholas30d30222020-09-11 12:27:26 -04001394 argType.columns() == type.rows()) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001395 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001396 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001397 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001398 if (argType.columns() == 1) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001399 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1400 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001401 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001402 SpvId componentType = this->getType(argType.componentType());
1403 for (int j = 0; j < argType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001404 SpvId swizzle = this->nextId();
1405 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1406 arguments[i], j, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001407 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1408 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001409 }
1410 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001411 }
1412 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001413 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001414 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001415 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001416 this->writeWord(result, out);
1417 for (SpvId id : columnIds) {
1418 this->writeWord(id, out);
1419 }
1420 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001421 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001422 return result;
1423}
1424
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001425SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001426 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001427 SkASSERT(type.isVector());
Brian Osmanb6b95732020-06-30 11:44:27 -04001428 if (c.isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001429 return this->writeConstantVector(c);
1430 }
1431 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1432 // an instruction
1433 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001434 for (size_t i = 0; i < c.arguments().size(); i++) {
1435 const Type& argType = c.arguments()[i]->type();
John Stiles9aeed132020-11-24 17:36:06 -05001436 if (argType.isVector()) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001437 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1438 // extract the components and convert them in that case manually. On top of that,
1439 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1440 // doesn't handle vector arguments at all, so we always extract vector components and
1441 // pass them into OpCreateComposite individually.
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001442 SpvId vec = this->writeExpression(*c.arguments()[i], out);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001443 SpvOp_ op = SpvOpUndef;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001444 const Type& src = argType.componentType();
1445 const Type& dst = type.componentType();
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001446 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1447 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001448 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001449 return vec;
1450 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001451 } else if (src == *fContext.fInt_Type ||
1452 src == *fContext.fShort_Type ||
1453 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001454 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001455 } else if (src == *fContext.fUInt_Type ||
1456 src == *fContext.fUShort_Type ||
1457 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001458 op = SpvOpConvertUToF;
1459 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001460 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001461 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001462 } else if (dst == *fContext.fInt_Type ||
1463 dst == *fContext.fShort_Type ||
1464 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001465 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1466 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001467 } else if (src == *fContext.fInt_Type ||
1468 src == *fContext.fShort_Type ||
1469 src == *fContext.fByte_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001470 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001471 return vec;
1472 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001473 } else if (src == *fContext.fUInt_Type ||
1474 src == *fContext.fUShort_Type ||
1475 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001476 op = SpvOpBitcast;
1477 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001478 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001479 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001480 } else if (dst == *fContext.fUInt_Type ||
1481 dst == *fContext.fUShort_Type ||
1482 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001483 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1484 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001485 } else if (src == *fContext.fInt_Type ||
1486 src == *fContext.fShort_Type ||
1487 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001488 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001489 } else if (src == *fContext.fUInt_Type ||
1490 src == *fContext.fUShort_Type ||
1491 src == *fContext.fUByte_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001492 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001493 return vec;
1494 }
1495 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001496 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001497 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001498 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001499 for (int j = 0; j < argType.columns(); j++) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001500 SpvId swizzle = this->nextId();
1501 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1502 out);
1503 if (op != SpvOpUndef) {
1504 SpvId cast = this->nextId();
1505 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1506 arguments.push_back(cast);
1507 } else {
1508 arguments.push_back(swizzle);
1509 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001510 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001511 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001512 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001513 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001514 }
1515 SpvId result = this->nextId();
John Stiles9aeed132020-11-24 17:36:06 -05001516 if (arguments.size() == 1 && c.arguments()[0]->type().isScalar()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001517 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(), out);
1518 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001519 this->writeWord(result, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001520 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001521 this->writeWord(arguments[0], out);
1522 }
1523 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001524 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001525 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001526 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001527 this->writeWord(result, out);
1528 for (SpvId id : arguments) {
1529 this->writeWord(id, out);
1530 }
1531 }
1532 return result;
1533}
1534
Ethan Nicholasbd553222017-07-18 15:54:59 -04001535SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001536 const Type& type = c.type();
1537 SkASSERT(type.typeKind() == Type::TypeKind::kArray);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001538 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1539 // an instruction
1540 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001541 for (size_t i = 0; i < c.arguments().size(); i++) {
1542 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholasbd553222017-07-18 15:54:59 -04001543 }
1544 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001545 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.arguments().size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001546 this->writeWord(this->getType(type), out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001547 this->writeWord(result, out);
1548 for (SpvId id : arguments) {
1549 this->writeWord(id, out);
1550 }
1551 return result;
1552}
1553
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001554SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001555 const Type& type = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001556 if (c.arguments().size() == 1 &&
1557 this->getActualType(type) == this->getActualType(c.arguments()[0]->type())) {
1558 return this->writeExpression(*c.arguments()[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001559 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001560 if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001561 return this->writeFloatConstructor(c, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001562 } else if (type == *fContext.fInt_Type ||
1563 type == *fContext.fShort_Type ||
1564 type == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001565 return this->writeIntConstructor(c, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001566 } else if (type == *fContext.fUInt_Type ||
1567 type == *fContext.fUShort_Type ||
1568 type == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001569 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001570 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001571 switch (type.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001572 case Type::TypeKind::kVector:
ethannicholasb3058bd2016-07-01 08:22:01 -07001573 return this->writeVectorConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001574 case Type::TypeKind::kMatrix:
ethannicholasb3058bd2016-07-01 08:22:01 -07001575 return this->writeMatrixConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001576 case Type::TypeKind::kArray:
Ethan Nicholasbd553222017-07-18 15:54:59 -04001577 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001578 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001579#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07001580 ABORT("unsupported constructor: %s", c.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001581#endif
1582 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001583 }
1584}
1585
1586SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1587 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001588 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001589 return SpvStorageClassInput;
1590 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001591 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001592 return SpvStorageClassOutput;
1593 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001594 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001595 return SpvStorageClassPushConstant;
1596 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001597 return SpvStorageClassUniform;
1598 } else {
1599 return SpvStorageClassFunction;
1600 }
1601}
1602
ethannicholasf789b382016-08-03 12:43:36 -07001603SpvStorageClass_ get_storage_class(const Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001604 switch (expr.kind()) {
1605 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -04001606 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001607 if (var.storage() != Variable::Storage::kGlobal) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001608 return SpvStorageClassFunction;
1609 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001610 SpvStorageClass_ result = get_storage_class(var.modifiers());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001611 if (result == SpvStorageClassFunction) {
1612 result = SpvStorageClassPrivate;
1613 }
1614 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001615 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001616 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001617 return get_storage_class(*expr.as<FieldAccess>().base());
Ethan Nicholase6592142020-09-08 10:22:09 -04001618 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001619 return get_storage_class(*expr.as<IndexExpression>().base());
ethannicholasb3058bd2016-07-01 08:22:01 -07001620 default:
1621 return SpvStorageClassFunction;
1622 }
1623}
1624
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001625std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001626 std::vector<SpvId> chain;
Ethan Nicholase6592142020-09-08 10:22:09 -04001627 switch (expr.kind()) {
1628 case Expression::Kind::kIndex: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001629 IndexExpression& indexExpr = (IndexExpression&) expr;
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001630 chain = this->getAccessChain(*indexExpr.base(), out);
1631 chain.push_back(this->writeExpression(*indexExpr.index(), out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001632 break;
1633 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001634 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001635 FieldAccess& fieldExpr = (FieldAccess&) expr;
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001636 chain = this->getAccessChain(*fieldExpr.base(), out);
1637 IntLiteral index(fContext, -1, fieldExpr.fieldIndex());
ethannicholasb3058bd2016-07-01 08:22:01 -07001638 chain.push_back(this->writeIntLiteral(index));
1639 break;
1640 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001641 default: {
1642 SpvId id = this->getLValue(expr, out)->getPointer();
1643 SkASSERT(id != 0);
1644 chain.push_back(id);
1645 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001646 }
1647 return chain;
1648}
1649
1650class PointerLValue : public SPIRVCodeGenerator::LValue {
1651public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001652 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1653 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001654 : fGen(gen)
1655 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001656 , fType(type)
1657 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001658
John Stiles1cf2c8d2020-08-13 22:58:04 -04001659 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001660 return fPointer;
1661 }
1662
John Stiles1cf2c8d2020-08-13 22:58:04 -04001663 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001664 SpvId result = fGen.nextId();
1665 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001666 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001667 return result;
1668 }
1669
John Stiles1cf2c8d2020-08-13 22:58:04 -04001670 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001671 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1672 }
1673
1674private:
1675 SPIRVCodeGenerator& fGen;
1676 const SpvId fPointer;
1677 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001678 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001679};
1680
1681class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1682public:
John Stiles750109b2020-10-30 13:45:46 -04001683 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const ComponentArray& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001684 const Type& baseType, const Type& swizzleType,
1685 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001686 : fGen(gen)
1687 , fVecPointer(vecPointer)
1688 , fComponents(components)
1689 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001690 , fSwizzleType(swizzleType)
1691 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001692
John Stiles1cf2c8d2020-08-13 22:58:04 -04001693 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001694 return 0;
1695 }
1696
John Stiles1cf2c8d2020-08-13 22:58:04 -04001697 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001698 SpvId base = fGen.nextId();
1699 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001700 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001701 SpvId result = fGen.nextId();
1702 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1703 fGen.writeWord(fGen.getType(fSwizzleType), out);
1704 fGen.writeWord(result, out);
1705 fGen.writeWord(base, out);
1706 fGen.writeWord(base, out);
1707 for (int component : fComponents) {
1708 fGen.writeWord(component, out);
1709 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001710 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001711 return result;
1712 }
1713
John Stiles1cf2c8d2020-08-13 22:58:04 -04001714 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001715 // use OpVectorShuffle to mix and match the vector components. We effectively create
1716 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001717 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001718 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001719 // float3L = ...;
1720 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001721 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001722 // 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 -07001723 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1724 // (3, 1, 4).
1725 SpvId base = fGen.nextId();
1726 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1727 SpvId shuffle = fGen.nextId();
1728 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1729 fGen.writeWord(fGen.getType(fBaseType), out);
1730 fGen.writeWord(shuffle, out);
1731 fGen.writeWord(base, out);
1732 fGen.writeWord(value, out);
1733 for (int i = 0; i < fBaseType.columns(); i++) {
1734 // current offset into the virtual vector, defaults to pulling the unmodified
1735 // value from the left side
1736 int offset = i;
1737 // check to see if we are writing this component
1738 for (size_t j = 0; j < fComponents.size(); j++) {
1739 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001740 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001741 // the correct component of the right side instead of preserving the
1742 // value from the left
1743 offset = (int) (j + fBaseType.columns());
1744 break;
1745 }
1746 }
1747 fGen.writeWord(offset, out);
1748 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001749 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001750 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1751 }
1752
1753private:
1754 SPIRVCodeGenerator& fGen;
1755 const SpvId fVecPointer;
John Stiles750109b2020-10-30 13:45:46 -04001756 const ComponentArray& fComponents;
ethannicholasb3058bd2016-07-01 08:22:01 -07001757 const Type& fBaseType;
1758 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001759 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001760};
1761
Greg Daniel64773e62016-11-22 09:44:03 -05001762std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001763 OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001764 const Type& type = expr.type();
1765 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
Ethan Nicholase6592142020-09-08 10:22:09 -04001766 switch (expr.kind()) {
1767 case Expression::Kind::kVariableReference: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001768 SpvId typeId;
Ethan Nicholas78686922020-10-08 06:46:27 -04001769 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001770 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001771 typeId = this->getType(Type("sk_in", Type::TypeKind::kArray,
1772 var.type().componentType(), fSkInCount));
Ethan Nicholas5226b772018-05-03 16:20:41 -04001773 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001774 typeId = this->getType(type);
Ethan Nicholas5226b772018-05-03 16:20:41 -04001775 }
ethannicholasd598f792016-07-25 10:08:54 -07001776 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001777 SkASSERT(entry != fVariableMap.end());
John Stiles5570c512020-11-19 17:58:07 -05001778 return std::make_unique<PointerLValue>(*this, entry->second, typeId, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001779 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001780 case Expression::Kind::kIndex: // fall through
1781 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001782 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1783 SpvId member = this->nextId();
1784 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001785 this->writeWord(this->getPointerType(type, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001786 this->writeWord(member, out);
1787 for (SpvId idx : chain) {
1788 this->writeWord(idx, out);
1789 }
John Stiles5570c512020-11-19 17:58:07 -05001790 return std::make_unique<PointerLValue>(*this, member, this->getType(type), precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001791 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001792 case Expression::Kind::kSwizzle: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001793 Swizzle& swizzle = (Swizzle&) expr;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001794 size_t count = swizzle.components().size();
1795 SpvId base = this->getLValue(*swizzle.base(), out)->getPointer();
John Stiles5570c512020-11-19 17:58:07 -05001796 if (!base) {
1797 fErrors.error(swizzle.fOffset, "unable to retrieve lvalue from swizzle");
1798 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001799 if (count == 1) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001800 IntLiteral index(fContext, -1, swizzle.components()[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001801 SpvId member = this->nextId();
1802 this->writeInstruction(SpvOpAccessChain,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001803 this->getPointerType(type,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001804 get_storage_class(*swizzle.base())),
Greg Daniel64773e62016-11-22 09:44:03 -05001805 member,
1806 base,
1807 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001808 out);
John Stiles5570c512020-11-19 17:58:07 -05001809 return std::make_unique<PointerLValue>(*this, member, this->getType(type),
1810 precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001811 } else {
John Stiles5570c512020-11-19 17:58:07 -05001812 return std::make_unique<SwizzleLValue>(*this, base, swizzle.components(),
1813 swizzle.base()->type(), type, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001814 }
1815 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001816 case Expression::Kind::kTernary: {
Ethan Nicholasa583b812018-01-18 13:32:11 -05001817 TernaryExpression& t = (TernaryExpression&) expr;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001818 SpvId test = this->writeExpression(*t.test(), out);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001819 SpvId end = this->nextId();
1820 SpvId ifTrueLabel = this->nextId();
1821 SpvId ifFalseLabel = this->nextId();
1822 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1823 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1824 this->writeLabel(ifTrueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04001825 SpvId ifTrue = this->getLValue(*t.ifTrue(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001826 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001827 this->writeInstruction(SpvOpBranch, end, out);
1828 ifTrueLabel = fCurrentBlock;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001829 SpvId ifFalse = this->getLValue(*t.ifFalse(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001830 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001831 ifFalseLabel = fCurrentBlock;
1832 this->writeInstruction(SpvOpBranch, end, out);
1833 SpvId result = this->nextId();
1834 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1835 ifTrueLabel, ifFalse, ifFalseLabel, out);
John Stiles5570c512020-11-19 17:58:07 -05001836 return std::make_unique<PointerLValue>(*this, result, this->getType(type), precision);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001837 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001838 default: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001839 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001840 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001841 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1842 // caught by IRGenerator
1843 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001844 SpvId pointerType = this->getPointerType(type, SpvStorageClassFunction);
1845 this->writeInstruction(SpvOpVariable, pointerType, result, SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001846 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001847 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
John Stiles5570c512020-11-19 17:58:07 -05001848 return std::make_unique<PointerLValue>(*this, result, this->getType(type), precision);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001849 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001850 }
1851}
1852
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001853SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001854 SpvId result = this->nextId();
Ethan Nicholas78686922020-10-08 06:46:27 -04001855 auto entry = fVariableMap.find(ref.variable());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001856 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001857 SpvId var = entry->second;
Ethan Nicholas78686922020-10-08 06:46:27 -04001858 this->writeInstruction(SpvOpLoad, this->getType(ref.variable()->type()), result, var, out);
1859 this->writePrecisionModifier(ref.variable()->type(), result);
1860 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
Greg Daniela85e4bf2020-06-17 16:32:45 -04001861 (fProgram.fSettings.fFlipY || fProgram.fSettings.fInverseW)) {
1862 // The x component never changes, so just grab it
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001863 SpvId xId = this->nextId();
1864 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1865 result, 0, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001866
1867 // Calculate the y component which may need to be flipped
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001868 SpvId rawYId = this->nextId();
1869 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1870 result, 1, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001871 SpvId flippedYId = 0;
1872 if (fProgram.fSettings.fFlipY) {
1873 // need to remap to a top-left coordinate system
1874 if (fRTHeightStructId == (SpvId)-1) {
1875 // height variable hasn't been written yet
Greg Daniela85e4bf2020-06-17 16:32:45 -04001876 SkASSERT(fRTHeightFieldIndex == (SpvId)-1);
1877 std::vector<Type::Field> fields;
John Stiles5570c512020-11-19 17:58:07 -05001878 if (fProgram.fSettings.fRTHeightOffset < 0) {
1879 fErrors.error(ref.fOffset, "RTHeightOffset is negative");
1880 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001881 fields.emplace_back(
1882 Modifiers(Layout(0, -1, fProgram.fSettings.fRTHeightOffset, -1, -1, -1, -1,
1883 -1, Layout::Format::kUnspecified,
1884 Layout::kUnspecified_Primitive, 1, -1, "", "",
1885 Layout::kNo_Key, Layout::CType::kDefault),
1886 0),
1887 SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1888 StringFragment name("sksl_synthetic_uniforms");
1889 Type intfStruct(-1, name, fields);
1890
1891 int binding = fProgram.fSettings.fRTHeightBinding;
John Stiles5570c512020-11-19 17:58:07 -05001892 if (binding == -1) {
1893 fErrors.error(ref.fOffset, "layout(binding=...) is required in SPIR-V");
1894 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001895 int set = fProgram.fSettings.fRTHeightSet;
John Stiles5570c512020-11-19 17:58:07 -05001896 if (set == -1) {
1897 fErrors.error(ref.fOffset, "layout(set=...) is required in SPIR-V");
1898 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001899 Layout layout(0, -1, -1, binding, -1, set, -1, -1, Layout::Format::kUnspecified,
1900 Layout::kUnspecified_Primitive, -1, -1, "", "", Layout::kNo_Key,
1901 Layout::CType::kDefault);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001902 Modifiers modifiers(layout, Modifiers::kUniform_Flag);
John Stiles3ae071e2020-08-05 15:29:29 -04001903 const Variable* intfVar = fSynthetics.takeOwnershipOfSymbol(
1904 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -05001905 fProgram.fModifiers->addToPool(modifiers),
John Stiles3ae071e2020-08-05 15:29:29 -04001906 name,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001907 &intfStruct,
Brian Osman3887a012020-09-30 13:22:27 -04001908 /*builtin=*/false,
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001909 Variable::Storage::kGlobal));
John Stilesd39aec02020-12-03 10:42:26 -05001910 InterfaceBlock intf(/*offset=*/-1, intfVar, name,
1911 /*instanceName=*/"", /*arraySize=*/0,
John Stiles7c3515b2020-10-16 18:38:39 -04001912 std::make_shared<SymbolTable>(&fErrors, /*builtin=*/false));
Stephen White88574972020-06-23 19:09:29 -04001913
1914 fRTHeightStructId = this->writeInterfaceBlock(intf, false);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001915 fRTHeightFieldIndex = 0;
Jim Van Verthf3ec9832020-10-21 16:09:57 -04001916 fRTHeightStorageClass = SpvStorageClassUniform;
Greg Daniela85e4bf2020-06-17 16:32:45 -04001917 }
1918 SkASSERT(fRTHeightFieldIndex != (SpvId)-1);
1919
1920 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1921 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1922 SpvId heightPtr = this->nextId();
1923 this->writeOpCode(SpvOpAccessChain, 5, out);
Jim Van Verthf3ec9832020-10-21 16:09:57 -04001924 this->writeWord(this->getPointerType(*fContext.fFloat_Type, fRTHeightStorageClass),
Greg Daniela85e4bf2020-06-17 16:32:45 -04001925 out);
1926 this->writeWord(heightPtr, out);
1927 this->writeWord(fRTHeightStructId, out);
1928 this->writeWord(fieldIndexId, out);
1929 SpvId heightRead = this->nextId();
1930 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1931 heightPtr, out);
1932
1933 flippedYId = this->nextId();
1934 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
1935 heightRead, rawYId, out);
1936 }
1937
1938 // The z component will always be zero so we just get an id to the 0 literal
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001939 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001940 SpvId zeroId = writeFloatLiteral(zero);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001941
1942 // Calculate the w component which may need to be inverted
1943 SpvId rawWId = this->nextId();
1944 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawWId,
Ethan Nicholas20798e52018-12-04 12:30:50 -05001945 result, 3, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001946 SpvId invWId = 0;
1947 if (fProgram.fSettings.fInverseW) {
1948 // We need to invert w
1949 FloatLiteral one(fContext, -1, 1.0);
1950 SpvId oneId = writeFloatLiteral(one);
1951 invWId = this->nextId();
1952 this->writeInstruction(SpvOpFDiv, this->getType(*fContext.fFloat_Type), invWId, oneId,
1953 rawWId, out);
1954 }
1955
1956 // Fill in the new fragcoord with the components from above
1957 SpvId adjusted = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001958 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001959 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001960 this->writeWord(adjusted, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001961 this->writeWord(xId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001962 if (fProgram.fSettings.fFlipY) {
1963 this->writeWord(flippedYId, out);
1964 } else {
1965 this->writeWord(rawYId, out);
1966 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001967 this->writeWord(zeroId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001968 if (fProgram.fSettings.fInverseW) {
1969 this->writeWord(invWId, out);
1970 } else {
1971 this->writeWord(rawWId, out);
1972 }
1973
1974 return adjusted;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001975 }
Ethan Nicholas78686922020-10-08 06:46:27 -04001976 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
Chris Daltonb91c4662018-08-01 10:46:22 -06001977 !fProgram.fSettings.fFlipY) {
1978 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1979 // the default convention of "counter-clockwise face is front".
1980 SpvId inverse = this->nextId();
1981 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1982 result, out);
1983 return inverse;
1984 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001985 return result;
1986}
1987
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001988SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05001989 if (expr.base()->type().isVector()) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001990 SpvId base = this->writeExpression(*expr.base(), out);
1991 SpvId index = this->writeExpression(*expr.index(), out);
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001992 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001993 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.type()), result, base,
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001994 index, out);
1995 return result;
1996 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001997 return getLValue(expr, out)->load(out);
1998}
1999
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002000SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002001 return getLValue(f, out)->load(out);
2002}
2003
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002004SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002005 SpvId base = this->writeExpression(*swizzle.base(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002006 SpvId result = this->nextId();
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002007 size_t count = swizzle.components().size();
ethannicholasb3058bd2016-07-01 08:22:01 -07002008 if (count == 1) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002009 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.type()), result, base,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002010 swizzle.components()[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002011 } else {
2012 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002013 this->writeWord(this->getType(swizzle.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002014 this->writeWord(result, out);
2015 this->writeWord(base, out);
Brian Osman25647672020-09-15 15:16:56 -04002016 this->writeWord(base, out);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002017 for (int component : swizzle.components()) {
Brian Osman25647672020-09-15 15:16:56 -04002018 this->writeWord(component, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002019 }
2020 }
2021 return result;
2022}
2023
Greg Daniel64773e62016-11-22 09:44:03 -05002024SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
2025 const Type& operandType, SpvId lhs,
2026 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002027 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002028 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002029 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002030 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002031 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002032 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002033 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002034 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
John Stiles4a7dc462020-11-25 11:08:08 -05002035 } else if (operandType.isBoolean()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002036 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002037 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07002038 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002039#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002040 ABORT("invalid operandType: %s", operandType.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002041#endif
ethannicholasb3058bd2016-07-01 08:22:01 -07002042 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04002043 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002044 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
2045 fDecorationBuffer);
2046 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002047 return result;
2048}
2049
Ethan Nicholas48e24052018-03-14 13:51:39 -04002050SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
2051 OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05002052 if (operandType.isVector()) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002053 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04002054 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002055 return result;
2056 }
2057 return id;
2058}
2059
Ethan Nicholas68990be2017-07-13 09:36:52 -04002060SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
2061 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002062 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04002063 OutputStream& out) {
2064 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
John Stiles9aeed132020-11-24 17:36:06 -05002065 SkASSERT(operandType.isMatrix());
Ethan Nicholas0df21132018-07-10 09:37:51 -04002066 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2067 operandType.rows(),
2068 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04002069 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002070 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04002071 1));
2072 SpvId boolType = this->getType(*fContext.fBool_Type);
2073 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04002074 for (int i = 0; i < operandType.columns(); i++) {
2075 SpvId columnL = this->nextId();
2076 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2077 SpvId columnR = this->nextId();
2078 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002079 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002080 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
2081 SpvId merge = this->nextId();
2082 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002083 if (result != 0) {
2084 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002085 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002086 result = next;
2087 }
2088 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002089 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04002090 }
2091 }
2092 return result;
2093}
2094
Ethan Nicholas0df21132018-07-10 09:37:51 -04002095SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
2096 SpvId rhs, SpvOp_ floatOperator,
2097 SpvOp_ intOperator,
2098 OutputStream& out) {
2099 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
John Stiles9aeed132020-11-24 17:36:06 -05002100 SkASSERT(operandType.isMatrix());
Ethan Nicholas0df21132018-07-10 09:37:51 -04002101 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2102 operandType.rows(),
2103 1));
2104 SpvId columns[4];
2105 for (int i = 0; i < operandType.columns(); i++) {
2106 SpvId columnL = this->nextId();
2107 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2108 SpvId columnR = this->nextId();
2109 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2110 columns[i] = this->nextId();
2111 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2112 }
2113 SpvId result = this->nextId();
2114 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2115 this->writeWord(this->getType(operandType), out);
2116 this->writeWord(result, out);
2117 for (int i = 0; i < operandType.columns(); i++) {
2118 this->writeWord(columns[i], out);
2119 }
2120 return result;
2121}
2122
Ethan Nicholas49465b42019-04-17 12:22:21 -04002123std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2124 if (type.isInteger()) {
2125 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002126 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002127 else if (type.isFloat()) {
2128 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002129 } else {
Ethan Nicholase2c49992020-10-05 11:49:11 -04002130 ABORT("math is unsupported on type '%s'", String(type.name()).c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002131 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002132}
2133
2134SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Token::Kind op,
2135 const Type& rightType, SpvId rhs,
2136 const Type& resultType, OutputStream& out) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002137 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002138 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002139 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2140 // handling in SPIR-V
Ethan Nicholas49465b42019-04-17 12:22:21 -04002141 if (this->getActualType(leftType) != this->getActualType(rightType)) {
John Stiles9aeed132020-11-24 17:36:06 -05002142 if (leftType.isVector() && rightType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002143 if (op == Token::Kind::TK_SLASH) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002144 SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
2145 SpvId inverse = this->nextId();
2146 this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
2147 rhs = inverse;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002148 op = Token::Kind::TK_STAR;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002149 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002150 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002151 SpvId result = this->nextId();
2152 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2153 result, lhs, rhs, out);
2154 return result;
2155 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002156 // promote number to vector
2157 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002158 const Type& vecType = leftType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002159 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2160 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002161 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002162 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002163 this->writeWord(rhs, out);
2164 }
2165 rhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002166 operandType = &leftType;
John Stiles9aeed132020-11-24 17:36:06 -05002167 } else if (rightType.isVector() && leftType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002168 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002169 SpvId result = this->nextId();
2170 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2171 result, rhs, lhs, out);
2172 return result;
2173 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002174 // promote number to vector
2175 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002176 const Type& vecType = rightType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002177 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2178 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002179 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002180 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002181 this->writeWord(lhs, out);
2182 }
2183 lhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002184 operandType = &rightType;
John Stiles9aeed132020-11-24 17:36:06 -05002185 } else if (leftType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002186 SpvOp_ spvop;
John Stiles9aeed132020-11-24 17:36:06 -05002187 if (rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002188 spvop = SpvOpMatrixTimesMatrix;
John Stiles9aeed132020-11-24 17:36:06 -05002189 } else if (rightType.isVector()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002190 spvop = SpvOpMatrixTimesVector;
ethannicholasb3058bd2016-07-01 08:22:01 -07002191 } else {
John Stiles9aeed132020-11-24 17:36:06 -05002192 SkASSERT(rightType.isScalar());
Ethan Nicholas49465b42019-04-17 12:22:21 -04002193 spvop = SpvOpMatrixTimesScalar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002194 }
2195 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002196 this->writeInstruction(spvop, this->getType(resultType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002197 return result;
John Stiles9aeed132020-11-24 17:36:06 -05002198 } else if (rightType.isMatrix()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002199 SpvId result = this->nextId();
John Stiles9aeed132020-11-24 17:36:06 -05002200 if (leftType.isVector()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002201 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(resultType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002202 lhs, rhs, out);
2203 } else {
John Stiles9aeed132020-11-24 17:36:06 -05002204 SkASSERT(leftType.isScalar());
Ethan Nicholas49465b42019-04-17 12:22:21 -04002205 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(resultType), result,
2206 rhs, lhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002207 }
2208 return result;
2209 } else {
John Stilesd8ca6b62020-11-23 14:28:36 -05002210 fErrors.error(leftType.fOffset, "unsupported mixed-type expression");
Ethan Nicholas49465b42019-04-17 12:22:21 -04002211 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002212 }
2213 } else {
John Stiles2d4f9592020-10-30 10:29:12 -04002214 operandType = &this->getActualType(leftType);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002215 SkASSERT(*operandType == this->getActualType(rightType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002216 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002217 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002218 case Token::Kind::TK_EQEQ: {
John Stiles9aeed132020-11-24 17:36:06 -05002219 if (operandType->isMatrix()) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002220 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002221 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002222 }
John Stiles4a7dc462020-11-25 11:08:08 -05002223 SkASSERT(resultType.isBoolean());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002224 const Type* tmpType;
John Stiles9aeed132020-11-24 17:36:06 -05002225 if (operandType->isVector()) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002226 tmpType = &fContext.fBool_Type->toCompound(fContext,
2227 operandType->columns(),
2228 operandType->rows());
2229 } else {
2230 tmpType = &resultType;
2231 }
2232 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002233 SpvOpFOrdEqual, SpvOpIEqual,
2234 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002235 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002236 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002237 case Token::Kind::TK_NEQ:
John Stiles9aeed132020-11-24 17:36:06 -05002238 if (operandType->isMatrix()) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002239 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002240 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002241 }
John Stiles4a7dc462020-11-25 11:08:08 -05002242 [[fallthrough]];
2243 case Token::Kind::TK_LOGICALXOR:
2244 SkASSERT(resultType.isBoolean());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002245 const Type* tmpType;
John Stiles9aeed132020-11-24 17:36:06 -05002246 if (operandType->isVector()) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002247 tmpType = &fContext.fBool_Type->toCompound(fContext,
2248 operandType->columns(),
2249 operandType->rows());
2250 } else {
2251 tmpType = &resultType;
2252 }
2253 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002254 SpvOpFOrdNotEqual, SpvOpINotEqual,
2255 SpvOpINotEqual, SpvOpLogicalNotEqual,
2256 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002257 *operandType, SpvOpAny, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002258 case Token::Kind::TK_GT:
John Stiles4a7dc462020-11-25 11:08:08 -05002259 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002260 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2261 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002262 SpvOpUGreaterThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002263 case Token::Kind::TK_LT:
John Stiles4a7dc462020-11-25 11:08:08 -05002264 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002265 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002266 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002267 case Token::Kind::TK_GTEQ:
John Stiles4a7dc462020-11-25 11:08:08 -05002268 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002269 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2270 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002271 SpvOpUGreaterThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002272 case Token::Kind::TK_LTEQ:
John Stiles4a7dc462020-11-25 11:08:08 -05002273 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002274 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2275 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002276 SpvOpULessThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002277 case Token::Kind::TK_PLUS:
John Stiles9aeed132020-11-24 17:36:06 -05002278 if (leftType.isMatrix() && rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002279 SkASSERT(leftType == rightType);
2280 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002281 SpvOpFAdd, SpvOpIAdd, out);
2282 }
Greg Daniel64773e62016-11-22 09:44:03 -05002283 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002284 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002285 case Token::Kind::TK_MINUS:
John Stiles9aeed132020-11-24 17:36:06 -05002286 if (leftType.isMatrix() && rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002287 SkASSERT(leftType == rightType);
2288 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002289 SpvOpFSub, SpvOpISub, out);
2290 }
Greg Daniel64773e62016-11-22 09:44:03 -05002291 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002292 SpvOpISub, SpvOpISub, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002293 case Token::Kind::TK_STAR:
John Stiles9aeed132020-11-24 17:36:06 -05002294 if (leftType.isMatrix() && rightType.isMatrix()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002295 // matrix multiply
2296 SpvId result = this->nextId();
2297 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2298 lhs, rhs, out);
2299 return result;
2300 }
Greg Daniel64773e62016-11-22 09:44:03 -05002301 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002302 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002303 case Token::Kind::TK_SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002304 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002305 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002306 case Token::Kind::TK_PERCENT:
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002307 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2308 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002309 case Token::Kind::TK_SHL:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002310 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2311 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2312 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002313 case Token::Kind::TK_SHR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002314 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2315 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2316 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002317 case Token::Kind::TK_BITWISEAND:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002318 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2319 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002320 case Token::Kind::TK_BITWISEOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002321 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2322 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002323 case Token::Kind::TK_BITWISEXOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002324 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2325 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002326 case Token::Kind::TK_COMMA:
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04002327 return rhs;
ethannicholasb3058bd2016-07-01 08:22:01 -07002328 default:
John Stiles5570c512020-11-19 17:58:07 -05002329 fErrors.error(0, "unsupported token");
Ethan Nicholas49465b42019-04-17 12:22:21 -04002330 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002331 }
2332}
2333
Ethan Nicholas49465b42019-04-17 12:22:21 -04002334SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
John Stiles2d4f9592020-10-30 10:29:12 -04002335 const Expression& left = *b.left();
2336 const Expression& right = *b.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002337 Token::Kind op = b.getOperator();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002338 // handle cases where we don't necessarily evaluate both LHS and RHS
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002339 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002340 case Token::Kind::TK_EQ: {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002341 SpvId rhs = this->writeExpression(right, out);
2342 this->getLValue(left, out)->store(rhs, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002343 return rhs;
2344 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002345 case Token::Kind::TK_LOGICALAND:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002346 return this->writeLogicalAnd(b, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002347 case Token::Kind::TK_LOGICALOR:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002348 return this->writeLogicalOr(b, out);
2349 default:
2350 break;
2351 }
2352
2353 std::unique_ptr<LValue> lvalue;
2354 SpvId lhs;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002355 if (Compiler::IsAssignment(op)) {
2356 lvalue = this->getLValue(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002357 lhs = lvalue->load(out);
2358 } else {
2359 lvalue = nullptr;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002360 lhs = this->writeExpression(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002361 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002362 SpvId rhs = this->writeExpression(right, out);
2363 SpvId result = this->writeBinaryExpression(left.type(), lhs, Compiler::RemoveAssignment(op),
2364 right.type(), rhs, b.type(), out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002365 if (lvalue) {
2366 lvalue->store(result, out);
2367 }
2368 return result;
2369}
2370
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002371SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002372 SkASSERT(a.getOperator() == Token::Kind::TK_LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002373 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002374 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
John Stiles2d4f9592020-10-30 10:29:12 -04002375 SpvId lhs = this->writeExpression(*a.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002376 SpvId rhsLabel = this->nextId();
2377 SpvId end = this->nextId();
2378 SpvId lhsBlock = fCurrentBlock;
2379 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2380 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2381 this->writeLabel(rhsLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04002382 SpvId rhs = this->writeExpression(*a.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002383 SpvId rhsBlock = fCurrentBlock;
2384 this->writeInstruction(SpvOpBranch, end, out);
2385 this->writeLabel(end, out);
2386 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002387 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002388 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002389 return result;
2390}
2391
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002392SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002393 SkASSERT(o.getOperator() == Token::Kind::TK_LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002394 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002395 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
John Stiles2d4f9592020-10-30 10:29:12 -04002396 SpvId lhs = this->writeExpression(*o.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002397 SpvId rhsLabel = this->nextId();
2398 SpvId end = this->nextId();
2399 SpvId lhsBlock = fCurrentBlock;
2400 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2401 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2402 this->writeLabel(rhsLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04002403 SpvId rhs = this->writeExpression(*o.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002404 SpvId rhsBlock = fCurrentBlock;
2405 this->writeInstruction(SpvOpBranch, end, out);
2406 this->writeLabel(end, out);
2407 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002408 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002409 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002410 return result;
2411}
2412
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002413SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002414 const Type& type = t.type();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002415 SpvId test = this->writeExpression(*t.test(), out);
2416 if (t.ifTrue()->type().columns() == 1 &&
2417 t.ifTrue()->isCompileTimeConstant() &&
2418 t.ifFalse()->isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002419 // both true and false are constants, can just use OpSelect
2420 SpvId result = this->nextId();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002421 SpvId trueId = this->writeExpression(*t.ifTrue(), out);
2422 SpvId falseId = this->writeExpression(*t.ifFalse(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002423 this->writeInstruction(SpvOpSelect, this->getType(type), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002424 out);
2425 return result;
2426 }
Greg Daniel64773e62016-11-22 09:44:03 -05002427 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002428 // Adreno. Switched to storing the result in a temp variable as glslang does.
2429 SpvId var = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002430 this->writeInstruction(SpvOpVariable, this->getPointerType(type, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002431 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002432 SpvId trueLabel = this->nextId();
2433 SpvId falseLabel = this->nextId();
2434 SpvId end = this->nextId();
2435 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2436 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2437 this->writeLabel(trueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002438 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifTrue(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002439 this->writeInstruction(SpvOpBranch, end, out);
2440 this->writeLabel(falseLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002441 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifFalse(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002442 this->writeInstruction(SpvOpBranch, end, out);
2443 this->writeLabel(end, out);
2444 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002445 this->writeInstruction(SpvOpLoad, this->getType(type), result, var, out);
2446 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002447 return result;
2448}
2449
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002450SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002451 const Type& type = p.type();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002452 if (p.getOperator() == Token::Kind::TK_MINUS) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002453 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002454 SpvId typeId = this->getType(type);
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002455 SpvId expr = this->writeExpression(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002456 if (is_float(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002457 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002458 } else if (is_signed(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002459 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2460 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002461#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002462 ABORT("unsupported prefix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002463#endif
Brian Salomon23356442018-11-30 15:33:19 -05002464 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002465 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002466 return result;
2467 }
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002468 switch (p.getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002469 case Token::Kind::TK_PLUS:
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002470 return this->writeExpression(*p.operand(), out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002471 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002472 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002473 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
2474 SpvId result = this->writeBinaryOperation(type, type, lv->load(out), one,
Greg Daniel64773e62016-11-22 09:44:03 -05002475 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002476 out);
2477 lv->store(result, out);
2478 return result;
2479 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002480 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002481 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002482 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
2483 SpvId result = this->writeBinaryOperation(type, type, lv->load(out), one, SpvOpFSub,
2484 SpvOpISub, SpvOpISub, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002485 lv->store(result, out);
2486 return result;
2487 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002488 case Token::Kind::TK_LOGICALNOT: {
John Stiles4a7dc462020-11-25 11:08:08 -05002489 SkASSERT(p.operand()->type().isBoolean());
ethannicholasb3058bd2016-07-01 08:22:01 -07002490 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002491 this->writeInstruction(SpvOpLogicalNot, this->getType(type), result,
2492 this->writeExpression(*p.operand(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002493 return result;
2494 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002495 case Token::Kind::TK_BITWISENOT: {
ethannicholas5961bc92016-10-12 06:39:56 -07002496 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002497 this->writeInstruction(SpvOpNot, this->getType(type), result,
2498 this->writeExpression(*p.operand(), out), out);
ethannicholas5961bc92016-10-12 06:39:56 -07002499 return result;
2500 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002501 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002502#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002503 ABORT("unsupported prefix expression: %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002504#endif
2505 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002506 }
2507}
2508
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002509SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002510 const Type& type = p.type();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002511 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002512 SpvId result = lv->load(out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002513 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002514 switch (p.getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002515 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002516 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002517 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2518 lv->store(temp, out);
2519 return result;
2520 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002521 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002522 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002523 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2524 lv->store(temp, out);
2525 return result;
2526 }
2527 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002528#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002529 ABORT("unsupported postfix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002530#endif
2531 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002532 }
2533}
2534
ethannicholasf789b382016-08-03 12:43:36 -07002535SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
Ethan Nicholas59d660c2020-09-28 09:18:15 -04002536 if (b.value()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002537 if (fBoolTrue == 0) {
2538 fBoolTrue = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002539 this->writeInstruction(SpvOpConstantTrue, this->getType(b.type()), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002540 fConstantBuffer);
2541 }
2542 return fBoolTrue;
2543 } else {
2544 if (fBoolFalse == 0) {
2545 fBoolFalse = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002546 this->writeInstruction(SpvOpConstantFalse, this->getType(b.type()), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002547 fConstantBuffer);
2548 }
2549 return fBoolFalse;
2550 }
2551}
2552
ethannicholasf789b382016-08-03 12:43:36 -07002553SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002554 const Type& type = i.type();
2555 ConstantType constantType;
John Stilesfd41d872020-11-25 22:39:45 -05002556 if (type == *fContext.fInt_Type || type.typeKind() == Type::TypeKind::kEnum) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002557 constantType = ConstantType::kInt;
2558 } else if (type == *fContext.fUInt_Type) {
2559 constantType = ConstantType::kUInt;
2560 } else if (type == *fContext.fShort_Type || type == *fContext.fByte_Type) {
2561 constantType = ConstantType::kShort;
2562 } else if (type == *fContext.fUShort_Type || type == *fContext.fUByte_Type) {
2563 constantType = ConstantType::kUShort;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002564 } else {
2565 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002566 }
Ethan Nicholase96cdd12020-09-28 16:27:18 -04002567 std::pair<ConstantValue, ConstantType> key(i.value(), constantType);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002568 auto entry = fNumberConstants.find(key);
2569 if (entry == fNumberConstants.end()) {
2570 SpvId result = this->nextId();
Ethan Nicholase96cdd12020-09-28 16:27:18 -04002571 this->writeInstruction(SpvOpConstant, this->getType(type), result, (SpvId) i.value(),
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002572 fConstantBuffer);
2573 fNumberConstants[key] = result;
2574 return result;
2575 }
2576 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002577}
2578
ethannicholasf789b382016-08-03 12:43:36 -07002579SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002580 const Type& type = f.type();
2581 ConstantType constantType;
2582 if (type == *fContext.fHalf_Type) {
2583 constantType = ConstantType::kHalf;
ethannicholasb3058bd2016-07-01 08:22:01 -07002584 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002585 constantType = ConstantType::kFloat;
ethannicholasb3058bd2016-07-01 08:22:01 -07002586 }
Ethan Nicholasa3f22f12020-10-01 12:13:17 -04002587 float value = (float) f.value();
2588 std::pair<ConstantValue, ConstantType> key(f.value(), constantType);
John Stiles8c578662020-06-01 15:32:47 +00002589 auto entry = fNumberConstants.find(key);
2590 if (entry == fNumberConstants.end()) {
2591 SpvId result = this->nextId();
2592 uint32_t bits;
2593 SkASSERT(sizeof(bits) == sizeof(value));
2594 memcpy(&bits, &value, sizeof(bits));
Ethan Nicholas30d30222020-09-11 12:27:26 -04002595 this->writeInstruction(SpvOpConstant, this->getType(type), result, bits,
John Stiles8c578662020-06-01 15:32:47 +00002596 fConstantBuffer);
2597 fNumberConstants[key] = result;
2598 return result;
2599 }
2600 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002601}
2602
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002603SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002604 SpvId result = fFunctionMap[&f];
Ethan Nicholased84b732020-10-08 11:45:44 -04002605 this->writeInstruction(SpvOpFunction, this->getType(f.returnType()), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002606 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04002607 this->writeInstruction(SpvOpName, result, f.name(), fNameBuffer);
Brian Osman5bf3e202020-10-13 10:34:18 -04002608 const std::vector<const Variable*>& parameters = f.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -04002609 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002610 SpvId id = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -04002611 fVariableMap[parameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002612 SpvId type;
Ethan Nicholased84b732020-10-08 11:45:44 -04002613 type = this->getPointerType(parameters[i]->type(), SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002614 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2615 }
2616 return result;
2617}
2618
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002619SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2620 fVariableBuffer.reset();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002621 SpvId result = this->writeFunctionStart(f.declaration(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002622 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002623 StringStream bodyBuffer;
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002624 this->writeBlock((Block&) *f.body(), bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002625 write_stringstream(fVariableBuffer, out);
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002626 if (f.declaration().name() == "main") {
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002627 write_stringstream(fGlobalInitializersBuffer, out);
2628 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002629 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002630 if (fCurrentBlock) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002631 if (f.declaration().returnType() == *fContext.fVoid_Type) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002632 this->writeInstruction(SpvOpReturn, out);
2633 } else {
2634 this->writeInstruction(SpvOpUnreachable, out);
2635 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002636 }
2637 this->writeInstruction(SpvOpFunctionEnd, out);
2638 return result;
2639}
2640
2641void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2642 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002643 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002644 fDecorationBuffer);
2645 }
2646 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002647 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002648 fDecorationBuffer);
2649 }
2650 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002651 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002652 fDecorationBuffer);
2653 }
2654 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002655 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002656 fDecorationBuffer);
2657 }
Greg Daniel64773e62016-11-22 09:44:03 -05002658 if (layout.fInputAttachmentIndex >= 0) {
2659 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2660 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002661 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002662 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002663 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002664 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002665 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002666 fDecorationBuffer);
2667 }
2668}
2669
2670void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2671 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002672 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002673 layout.fLocation, fDecorationBuffer);
2674 }
2675 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002676 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002677 layout.fBinding, fDecorationBuffer);
2678 }
2679 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002680 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002681 layout.fIndex, fDecorationBuffer);
2682 }
2683 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002684 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002685 layout.fSet, fDecorationBuffer);
2686 }
Greg Daniel64773e62016-11-22 09:44:03 -05002687 if (layout.fInputAttachmentIndex >= 0) {
2688 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2689 layout.fInputAttachmentIndex, fDecorationBuffer);
2690 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002691 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002692 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002693 layout.fBuiltin, fDecorationBuffer);
2694 }
2695}
2696
Ethan Nicholas81d15112018-07-13 12:48:50 -04002697static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2698 switch (m.fLayout.fPrimitive) {
2699 case Layout::kPoints_Primitive:
2700 *outSkInCount = 1;
2701 break;
2702 case Layout::kLines_Primitive:
2703 *outSkInCount = 2;
2704 break;
2705 case Layout::kLinesAdjacency_Primitive:
2706 *outSkInCount = 4;
2707 break;
2708 case Layout::kTriangles_Primitive:
2709 *outSkInCount = 3;
2710 break;
2711 case Layout::kTrianglesAdjacency_Primitive:
2712 *outSkInCount = 6;
2713 break;
2714 default:
2715 return;
2716 }
2717}
2718
Stephen White88574972020-06-23 19:09:29 -04002719SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf, bool appendRTHeight) {
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002720 bool isBuffer = ((intf.variable().modifiers().fFlags & Modifiers::kBuffer_Flag) != 0);
2721 bool pushConstant = ((intf.variable().modifiers().fLayout.fFlags &
2722 Layout::kPushConstant_Flag) != 0);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002723 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2724 MemoryLayout(MemoryLayout::k430_Standard) :
2725 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002726 SpvId result = this->nextId();
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002727 const Type* type = &intf.variable().type();
John Stiles21f5f452020-11-30 09:57:59 -05002728 if (!MemoryLayout::LayoutIsSupported(*type)) {
John Stiles0023c0c2020-11-16 13:32:18 -05002729 fErrors.error(type->fOffset, "type '" + type->name() + "' is not permitted here");
2730 return this->nextId();
2731 }
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002732 Modifiers intfModifiers = intf.variable().modifiers();
2733 SpvStorageClass_ storageClass = get_storage_class(intfModifiers);
Stephen White88574972020-06-23 19:09:29 -04002734 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Greg Daniele6ab9982018-08-22 13:56:32 +00002735 SkASSERT(fRTHeightStructId == (SpvId) -1);
2736 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002737 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002738 fRTHeightStructId = result;
2739 fRTHeightFieldIndex = fields.size();
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002740 fRTHeightStorageClass = storageClass;
Greg Daniele6ab9982018-08-22 13:56:32 +00002741 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002742 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002743 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002744 SpvId typeId;
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002745 if (intfModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osman133724c2020-10-28 14:14:39 -04002746 for (const ProgramElement* e : fProgram.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04002747 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04002748 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholas81d15112018-07-13 12:48:50 -04002749 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002750 }
2751 }
Ethan Nicholase6592142020-09-08 10:22:09 -04002752 typeId = this->getType(Type("sk_in", Type::TypeKind::kArray,
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002753 intf.variable().type().componentType(),
Ethan Nicholase6592142020-09-08 10:22:09 -04002754 fSkInCount),
2755 memoryLayout);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002756 } else {
2757 typeId = this->getType(*type, memoryLayout);
2758 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002759 if (intfModifiers.fFlags & Modifiers::kBuffer_Flag) {
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002760 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002761 } else if (intfModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002762 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002763 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002764 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002765 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002766 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002767 Layout layout = intfModifiers.fLayout;
2768 if (intfModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002769 layout.fSet = 0;
2770 }
2771 this->writeLayout(layout, result);
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002772 fVariableMap[&intf.variable()] = result;
Stephen White88574972020-06-23 19:09:29 -04002773 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002774 delete type;
2775 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002776 return result;
2777}
2778
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002779void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002780 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2781}
2782
2783void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2784 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002785 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2786 }
2787}
2788
Brian Osman010ce6a2020-10-19 16:34:10 -04002789bool is_dead(const Variable& var, const ProgramUsage* usage) {
2790 ProgramUsage::VariableCounts counts = usage->get(var);
2791 if (counts.fRead || counts.fWrite) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002792 return false;
2793 }
2794 // not entirely sure what the rules are for when it's safe to elide interface variables, but it
2795 // causes various problems to elide some of them even when dead. But it also causes problems
2796 // *not* to elide sk_SampleMask when it's not being used.
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002797 if (!(var.modifiers().fFlags & (Modifiers::kIn_Flag |
2798 Modifiers::kOut_Flag |
2799 Modifiers::kUniform_Flag |
2800 Modifiers::kBuffer_Flag))) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002801 return true;
2802 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002803 return var.modifiers().fLayout.fBuiltin == SK_SAMPLEMASK_BUILTIN;
Chris Dalton2284aab2019-11-15 11:02:24 -07002804}
2805
ethannicholas5961bc92016-10-12 06:39:56 -07002806#define BUILTIN_IGNORE 9999
Brian Osmanc0213602020-10-06 14:43:32 -04002807void SPIRVCodeGenerator::writeGlobalVar(Program::Kind kind, const VarDeclaration& varDecl,
2808 OutputStream& out) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002809 const Variable& var = varDecl.var();
Brian Osmanc0213602020-10-06 14:43:32 -04002810 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2811 // in the OpenGL backend.
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002812 SkASSERT(!(var.modifiers().fFlags & (Modifiers::kReadOnly_Flag |
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002813 Modifiers::kWriteOnly_Flag |
2814 Modifiers::kCoherent_Flag |
2815 Modifiers::kVolatile_Flag |
2816 Modifiers::kRestrict_Flag)));
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002817 if (var.modifiers().fLayout.fBuiltin == BUILTIN_IGNORE) {
Brian Osmanc0213602020-10-06 14:43:32 -04002818 return;
2819 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002820 if (var.modifiers().fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
Brian Osmanc0213602020-10-06 14:43:32 -04002821 kind != Program::kFragment_Kind) {
2822 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
2823 return;
2824 }
Brian Osman010ce6a2020-10-19 16:34:10 -04002825 if (is_dead(var, fProgram.fUsage.get())) {
Brian Osmanc0213602020-10-06 14:43:32 -04002826 return;
2827 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002828 const Type& type = var.type();
Brian Osmanc0213602020-10-06 14:43:32 -04002829 SpvStorageClass_ storageClass;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002830 if (var.modifiers().fFlags & Modifiers::kIn_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002831 storageClass = SpvStorageClassInput;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002832 } else if (var.modifiers().fFlags & Modifiers::kOut_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002833 storageClass = SpvStorageClassOutput;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002834 } else if (var.modifiers().fFlags & Modifiers::kUniform_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002835 if (type.typeKind() == Type::TypeKind::kSampler ||
2836 type.typeKind() == Type::TypeKind::kSeparateSampler ||
2837 type.typeKind() == Type::TypeKind::kTexture) {
2838 storageClass = SpvStorageClassUniformConstant;
ethannicholasb3058bd2016-07-01 08:22:01 -07002839 } else {
Brian Osmanc0213602020-10-06 14:43:32 -04002840 storageClass = SpvStorageClassUniform;
ethannicholasb3058bd2016-07-01 08:22:01 -07002841 }
Brian Osmanc0213602020-10-06 14:43:32 -04002842 } else {
2843 storageClass = SpvStorageClassPrivate;
2844 }
2845 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002846 fVariableMap[&var] = id;
Brian Osmanc0213602020-10-06 14:43:32 -04002847 SpvId typeId;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002848 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osmanc0213602020-10-06 14:43:32 -04002849 typeId = this->getPointerType(
2850 Type("sk_in", Type::TypeKind::kArray, type.componentType(), fSkInCount),
2851 storageClass);
2852 } else {
2853 typeId = this->getPointerType(type, storageClass);
2854 }
2855 this->writeInstruction(SpvOpVariable, typeId, id, storageClass, fConstantBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002856 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002857 this->writePrecisionModifier(type, id);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002858 if (varDecl.value()) {
Brian Osmanc0213602020-10-06 14:43:32 -04002859 SkASSERT(!fCurrentBlock);
2860 fCurrentBlock = -1;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002861 SpvId value = this->writeExpression(*varDecl.value(), fGlobalInitializersBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002862 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
2863 fCurrentBlock = 0;
2864 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002865 this->writeLayout(var.modifiers().fLayout, id);
2866 if (var.modifiers().fFlags & Modifiers::kFlat_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002867 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2868 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002869 if (var.modifiers().fFlags & Modifiers::kNoPerspective_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002870 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2871 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002872 }
2873}
2874
Brian Osmanc0213602020-10-06 14:43:32 -04002875void SPIRVCodeGenerator::writeVarDeclaration(const VarDeclaration& varDecl, OutputStream& out) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002876 const Variable& var = varDecl.var();
Brian Osmanc0213602020-10-06 14:43:32 -04002877 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2878 // in the OpenGL backend.
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002879 SkASSERT(!(var.modifiers().fFlags & (Modifiers::kReadOnly_Flag |
2880 Modifiers::kWriteOnly_Flag |
2881 Modifiers::kCoherent_Flag |
2882 Modifiers::kVolatile_Flag |
2883 Modifiers::kRestrict_Flag)));
Brian Osmanc0213602020-10-06 14:43:32 -04002884 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002885 fVariableMap[&var] = id;
2886 SpvId type = this->getPointerType(var.type(), SpvStorageClassFunction);
Brian Osmanc0213602020-10-06 14:43:32 -04002887 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002888 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
2889 if (varDecl.value()) {
2890 SpvId value = this->writeExpression(*varDecl.value(), out);
Brian Osmanc0213602020-10-06 14:43:32 -04002891 this->writeInstruction(SpvOpStore, id, value, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002892 }
2893}
2894
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002895void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002896 switch (s.kind()) {
John Stiles98c1f822020-09-09 14:18:53 -04002897 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04002898 case Statement::Kind::kNop:
Ethan Nicholascb670962017-04-20 19:31:52 -04002899 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002900 case Statement::Kind::kBlock:
ethannicholasb3058bd2016-07-01 08:22:01 -07002901 this->writeBlock((Block&) s, out);
2902 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002903 case Statement::Kind::kExpression:
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04002904 this->writeExpression(*s.as<ExpressionStatement>().expression(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002905 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002906 case Statement::Kind::kReturn:
John Stiles26f98502020-08-18 09:30:51 -04002907 this->writeReturnStatement(s.as<ReturnStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002908 break;
Brian Osmanc0213602020-10-06 14:43:32 -04002909 case Statement::Kind::kVarDeclaration:
2910 this->writeVarDeclaration(s.as<VarDeclaration>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002911 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002912 case Statement::Kind::kIf:
John Stiles26f98502020-08-18 09:30:51 -04002913 this->writeIfStatement(s.as<IfStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002914 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002915 case Statement::Kind::kFor:
John Stiles26f98502020-08-18 09:30:51 -04002916 this->writeForStatement(s.as<ForStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002917 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002918 case Statement::Kind::kWhile:
John Stiles26f98502020-08-18 09:30:51 -04002919 this->writeWhileStatement(s.as<WhileStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002920 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002921 case Statement::Kind::kDo:
John Stiles26f98502020-08-18 09:30:51 -04002922 this->writeDoStatement(s.as<DoStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002923 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002924 case Statement::Kind::kSwitch:
John Stiles26f98502020-08-18 09:30:51 -04002925 this->writeSwitchStatement(s.as<SwitchStatement>(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002926 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002927 case Statement::Kind::kBreak:
ethannicholasb3058bd2016-07-01 08:22:01 -07002928 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2929 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002930 case Statement::Kind::kContinue:
ethannicholasb3058bd2016-07-01 08:22:01 -07002931 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2932 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002933 case Statement::Kind::kDiscard:
ethannicholasb3058bd2016-07-01 08:22:01 -07002934 this->writeInstruction(SpvOpKill, out);
2935 break;
2936 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002937#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002938 ABORT("unsupported statement: %s", s.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002939#endif
2940 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002941 }
2942}
2943
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002944void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04002945 for (const std::unique_ptr<Statement>& stmt : b.children()) {
2946 this->writeStatement(*stmt, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002947 }
2948}
2949
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002950void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002951 SpvId test = this->writeExpression(*stmt.test(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002952 SpvId ifTrue = this->nextId();
2953 SpvId ifFalse = this->nextId();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002954 if (stmt.ifFalse()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002955 SpvId end = this->nextId();
2956 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2957 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2958 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002959 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002960 if (fCurrentBlock) {
2961 this->writeInstruction(SpvOpBranch, end, out);
2962 }
2963 this->writeLabel(ifFalse, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002964 this->writeStatement(*stmt.ifFalse(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002965 if (fCurrentBlock) {
2966 this->writeInstruction(SpvOpBranch, end, out);
2967 }
2968 this->writeLabel(end, out);
2969 } else {
2970 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2971 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2972 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002973 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002974 if (fCurrentBlock) {
2975 this->writeInstruction(SpvOpBranch, ifFalse, out);
2976 }
2977 this->writeLabel(ifFalse, out);
2978 }
2979}
2980
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002981void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04002982 if (f.initializer()) {
2983 this->writeStatement(*f.initializer(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002984 }
2985 SpvId header = this->nextId();
2986 SpvId start = this->nextId();
2987 SpvId body = this->nextId();
2988 SpvId next = this->nextId();
2989 fContinueTarget.push(next);
2990 SpvId end = this->nextId();
2991 fBreakTarget.push(end);
2992 this->writeInstruction(SpvOpBranch, header, out);
2993 this->writeLabel(header, out);
2994 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002995 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002996 this->writeLabel(start, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04002997 if (f.test()) {
2998 SpvId test = this->writeExpression(*f.test(), out);
ethannicholas22f939e2016-10-13 13:25:34 -07002999 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
3000 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003001 this->writeLabel(body, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003002 this->writeStatement(*f.statement(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003003 if (fCurrentBlock) {
3004 this->writeInstruction(SpvOpBranch, next, out);
3005 }
3006 this->writeLabel(next, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003007 if (f.next()) {
3008 this->writeExpression(*f.next(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003009 }
3010 this->writeInstruction(SpvOpBranch, header, out);
3011 this->writeLabel(end, out);
3012 fBreakTarget.pop();
3013 fContinueTarget.pop();
3014}
3015
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003016void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003017 SpvId header = this->nextId();
3018 SpvId start = this->nextId();
3019 SpvId body = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003020 SpvId continueTarget = this->nextId();
3021 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003022 SpvId end = this->nextId();
3023 fBreakTarget.push(end);
3024 this->writeInstruction(SpvOpBranch, header, out);
3025 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003026 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003027 this->writeInstruction(SpvOpBranch, start, out);
3028 this->writeLabel(start, out);
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003029 SpvId test = this->writeExpression(*w.test(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003030 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
3031 this->writeLabel(body, out);
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003032 this->writeStatement(*w.statement(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003033 if (fCurrentBlock) {
Ethan Nicholas0d997662019-04-08 09:46:01 -04003034 this->writeInstruction(SpvOpBranch, continueTarget, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003035 }
Ethan Nicholas0d997662019-04-08 09:46:01 -04003036 this->writeLabel(continueTarget, out);
3037 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003038 this->writeLabel(end, out);
3039 fBreakTarget.pop();
3040 fContinueTarget.pop();
3041}
3042
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003043void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003044 SpvId header = this->nextId();
3045 SpvId start = this->nextId();
3046 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003047 SpvId continueTarget = this->nextId();
3048 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003049 SpvId end = this->nextId();
3050 fBreakTarget.push(end);
3051 this->writeInstruction(SpvOpBranch, header, out);
3052 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003053 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003054 this->writeInstruction(SpvOpBranch, start, out);
3055 this->writeLabel(start, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003056 this->writeStatement(*d.statement(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003057 if (fCurrentBlock) {
3058 this->writeInstruction(SpvOpBranch, next, out);
3059 }
3060 this->writeLabel(next, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003061 SpvId test = this->writeExpression(*d.test(), out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003062 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
3063 this->writeLabel(continueTarget, out);
3064 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003065 this->writeLabel(end, out);
3066 fBreakTarget.pop();
3067 fContinueTarget.pop();
3068}
3069
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003070void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04003071 SpvId value = this->writeExpression(*s.value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003072 std::vector<SpvId> labels;
3073 SpvId end = this->nextId();
3074 SpvId defaultLabel = end;
3075 fBreakTarget.push(end);
3076 int size = 3;
John Stiles2d4f9592020-10-30 10:29:12 -04003077 auto& cases = s.cases();
3078 for (const std::unique_ptr<SwitchCase>& c : cases) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003079 SpvId label = this->nextId();
3080 labels.push_back(label);
John Stiles2d4f9592020-10-30 10:29:12 -04003081 if (c->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003082 size += 2;
3083 } else {
3084 defaultLabel = label;
3085 }
3086 }
3087 labels.push_back(end);
3088 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3089 this->writeOpCode(SpvOpSwitch, size, out);
3090 this->writeWord(value, out);
3091 this->writeWord(defaultLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04003092 for (size_t i = 0; i < cases.size(); ++i) {
3093 if (!cases[i]->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003094 continue;
3095 }
John Stiles2d4f9592020-10-30 10:29:12 -04003096 this->writeWord(cases[i]->value()->as<IntLiteral>().value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003097 this->writeWord(labels[i], out);
3098 }
John Stiles2d4f9592020-10-30 10:29:12 -04003099 for (size_t i = 0; i < cases.size(); ++i) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003100 this->writeLabel(labels[i], out);
John Stiles2d4f9592020-10-30 10:29:12 -04003101 for (const auto& stmt : cases[i]->statements()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003102 this->writeStatement(*stmt, out);
3103 }
3104 if (fCurrentBlock) {
3105 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3106 }
3107 }
3108 this->writeLabel(end, out);
3109 fBreakTarget.pop();
3110}
3111
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003112void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003113 if (r.expression()) {
3114 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.expression(), out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003115 out);
3116 } else {
3117 this->writeInstruction(SpvOpReturn, out);
3118 }
3119}
3120
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003121void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003122 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003123 int invocations = 1;
Brian Osman133724c2020-10-28 14:14:39 -04003124 for (const ProgramElement* e : fProgram.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003125 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04003126 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003127 if (m.fFlags & Modifiers::kIn_Flag) {
3128 if (m.fLayout.fInvocations != -1) {
3129 invocations = m.fLayout.fInvocations;
3130 }
3131 SpvId input;
3132 switch (m.fLayout.fPrimitive) {
3133 case Layout::kPoints_Primitive:
3134 input = SpvExecutionModeInputPoints;
3135 break;
3136 case Layout::kLines_Primitive:
3137 input = SpvExecutionModeInputLines;
3138 break;
3139 case Layout::kLinesAdjacency_Primitive:
3140 input = SpvExecutionModeInputLinesAdjacency;
3141 break;
3142 case Layout::kTriangles_Primitive:
3143 input = SpvExecutionModeTriangles;
3144 break;
3145 case Layout::kTrianglesAdjacency_Primitive:
3146 input = SpvExecutionModeInputTrianglesAdjacency;
3147 break;
3148 default:
3149 input = 0;
3150 break;
3151 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003152 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003153 if (input) {
3154 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3155 }
3156 } else if (m.fFlags & Modifiers::kOut_Flag) {
3157 SpvId output;
3158 switch (m.fLayout.fPrimitive) {
3159 case Layout::kPoints_Primitive:
3160 output = SpvExecutionModeOutputPoints;
3161 break;
3162 case Layout::kLineStrip_Primitive:
3163 output = SpvExecutionModeOutputLineStrip;
3164 break;
3165 case Layout::kTriangleStrip_Primitive:
3166 output = SpvExecutionModeOutputTriangleStrip;
3167 break;
3168 default:
3169 output = 0;
3170 break;
3171 }
3172 if (output) {
3173 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3174 }
3175 if (m.fLayout.fMaxVertices != -1) {
3176 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3177 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3178 out);
3179 }
3180 }
3181 }
3182 }
3183 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3184 invocations, out);
3185}
3186
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003187void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003188 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003189 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003190 std::set<SpvId> interfaceVars;
Brian Osman1f8f5752020-10-28 14:46:21 -04003191 // assign IDs to functions
Brian Osman133724c2020-10-28 14:14:39 -04003192 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003193 switch (e->kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04003194 case ProgramElement::Kind::kFunction: {
Brian Osman1179fcf2020-10-08 16:04:40 -04003195 const FunctionDefinition& f = e->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04003196 fFunctionMap[&f.declaration()] = this->nextId();
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003197 break;
3198 }
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003199 default:
3200 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003201 }
3202 }
Brian Osman133724c2020-10-28 14:14:39 -04003203 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003204 if (e->is<InterfaceBlock>()) {
Brian Osman1f8f5752020-10-28 14:46:21 -04003205 const InterfaceBlock& intf = e->as<InterfaceBlock>();
ethannicholasb3058bd2016-07-01 08:22:01 -07003206 SpvId id = this->writeInterfaceBlock(intf);
Brian Osman1f8f5752020-10-28 14:46:21 -04003207
3208 const Modifiers& modifiers = intf.variable().modifiers();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003209 if (((modifiers.fFlags & Modifiers::kIn_Flag) ||
3210 (modifiers.fFlags & Modifiers::kOut_Flag)) &&
3211 modifiers.fLayout.fBuiltin == -1 &&
Brian Osman010ce6a2020-10-19 16:34:10 -04003212 !is_dead(intf.variable(), fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003213 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003214 }
3215 }
3216 }
Brian Osman133724c2020-10-28 14:14:39 -04003217 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003218 if (e->is<GlobalVarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04003219 this->writeGlobalVar(program.fKind,
3220 e->as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>(),
3221 body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003222 }
3223 }
Brian Osman133724c2020-10-28 14:14:39 -04003224 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003225 if (e->is<FunctionDefinition>()) {
3226 this->writeFunction(e->as<FunctionDefinition>(), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003227 }
3228 }
ethannicholasd598f792016-07-25 10:08:54 -07003229 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003230 for (auto entry : fFunctionMap) {
Ethan Nicholase2c49992020-10-05 11:49:11 -04003231 if (entry.first->name() == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003232 main = entry.first;
3233 }
3234 }
Ethan Nicholas1a668d22019-04-18 10:37:40 -04003235 if (!main) {
3236 fErrors.error(0, "program does not contain a main() function");
3237 return;
3238 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003239 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003240 const Variable* var = entry.first;
Ethan Nicholas453f67f2020-10-09 10:43:45 -04003241 if (var->storage() == Variable::Storage::kGlobal &&
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003242 ((var->modifiers().fFlags & Modifiers::kIn_Flag) ||
Brian Osman010ce6a2020-10-19 16:34:10 -04003243 (var->modifiers().fFlags & Modifiers::kOut_Flag)) &&
3244 !is_dead(*var, fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003245 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003246 }
3247 }
3248 this->writeCapabilities(out);
3249 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3250 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003251 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->name().fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003252 (int32_t) interfaceVars.size(), out);
3253 switch (program.fKind) {
3254 case Program::kVertex_Kind:
3255 this->writeWord(SpvExecutionModelVertex, out);
3256 break;
3257 case Program::kFragment_Kind:
3258 this->writeWord(SpvExecutionModelFragment, out);
3259 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003260 case Program::kGeometry_Kind:
3261 this->writeWord(SpvExecutionModelGeometry, out);
3262 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003263 default:
3264 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003265 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003266 SpvId entryPoint = fFunctionMap[main];
3267 this->writeWord(entryPoint, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003268 this->writeString(main->name().fChars, main->name().fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003269 for (int var : interfaceVars) {
3270 this->writeWord(var, out);
3271 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003272 if (program.fKind == Program::kGeometry_Kind) {
3273 this->writeGeometryShaderExecutionMode(entryPoint, out);
3274 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003275 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003276 this->writeInstruction(SpvOpExecutionMode,
3277 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003278 SpvExecutionModeOriginUpperLeft,
3279 out);
3280 }
Brian Osman133724c2020-10-28 14:14:39 -04003281 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003282 if (e->is<Extension>()) {
3283 this->writeInstruction(SpvOpSourceExtension, e->as<Extension>().name().c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003284 }
3285 }
Greg Daniel64773e62016-11-22 09:44:03 -05003286
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003287 write_stringstream(fExtraGlobalsBuffer, out);
3288 write_stringstream(fNameBuffer, out);
3289 write_stringstream(fDecorationBuffer, out);
3290 write_stringstream(fConstantBuffer, out);
3291 write_stringstream(fExternalFunctionsBuffer, out);
3292 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003293}
3294
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003295bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003296 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003297 this->writeWord(SpvMagicNumber, *fOut);
3298 this->writeWord(SpvVersion, *fOut);
3299 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003300 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003301 this->writeInstructions(fProgram, buffer);
3302 this->writeWord(fIdCount, *fOut);
3303 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003304 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003305 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003306}
3307
John Stilesa6841be2020-08-06 14:11:56 -04003308} // namespace SkSL