blob: 2d573419d9011f17b3c94e8c1cdc157b9b651dd9 [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);
John Stilesa07338f2020-12-17 12:39:08 -050068 fIntrinsicMap[String("outerProduct")] = ALL_SPIRV(OuterProduct);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040069 fIntrinsicMap[String("transpose")] = ALL_SPIRV(Transpose);
John Stiles3679cd12020-12-09 16:22:12 -050070 fIntrinsicMap[String("isinf")] = ALL_SPIRV(IsInf);
71 fIntrinsicMap[String("isnan")] = ALL_SPIRV(IsNan);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040072 fIntrinsicMap[String("inversesqrt")] = ALL_GLSL(InverseSqrt);
73 fIntrinsicMap[String("determinant")] = ALL_GLSL(Determinant);
74 fIntrinsicMap[String("matrixInverse")] = ALL_GLSL(MatrixInverse);
Ethan Nicholas70a44b22017-11-30 09:09:16 -050075 fIntrinsicMap[String("mod")] = SPECIAL(Mod);
John Stiles01957272020-12-09 17:14:47 -050076 fIntrinsicMap[String("modf")] = ALL_GLSL(Modf);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050077 fIntrinsicMap[String("min")] = SPECIAL(Min);
78 fIntrinsicMap[String("max")] = SPECIAL(Max);
79 fIntrinsicMap[String("clamp")] = SPECIAL(Clamp);
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040080 fIntrinsicMap[String("saturate")] = SPECIAL(Saturate);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040081 fIntrinsicMap[String("dot")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
Ethan Nicholas0187ae62017-05-03 11:03:44 -040082 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050083 fIntrinsicMap[String("mix")] = SPECIAL(Mix);
Brian Osman6ba3be12020-11-13 16:32:52 -050084 fIntrinsicMap[String("step")] = SPECIAL(Step);
85 fIntrinsicMap[String("smoothstep")] = SPECIAL(SmoothStep);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040086 fIntrinsicMap[String("fma")] = ALL_GLSL(Fma);
87 fIntrinsicMap[String("frexp")] = ALL_GLSL(Frexp);
88 fIntrinsicMap[String("ldexp")] = ALL_GLSL(Ldexp);
ethannicholasb3058bd2016-07-01 08:22:01 -070089
Ethan Nicholas0df1b042017-03-31 13:56:23 -040090#define PACK(type) fIntrinsicMap[String("pack" #type)] = ALL_GLSL(Pack ## type); \
91 fIntrinsicMap[String("unpack" #type)] = ALL_GLSL(Unpack ## type)
ethannicholasb3058bd2016-07-01 08:22:01 -070092 PACK(Snorm4x8);
93 PACK(Unorm4x8);
94 PACK(Snorm2x16);
95 PACK(Unorm2x16);
96 PACK(Half2x16);
97 PACK(Double2x32);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040098 fIntrinsicMap[String("length")] = ALL_GLSL(Length);
99 fIntrinsicMap[String("distance")] = ALL_GLSL(Distance);
100 fIntrinsicMap[String("cross")] = ALL_GLSL(Cross);
101 fIntrinsicMap[String("normalize")] = ALL_GLSL(Normalize);
John Stiles0d19fb42020-12-10 17:04:37 -0500102 fIntrinsicMap[String("faceforward")] = ALL_GLSL(FaceForward);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400103 fIntrinsicMap[String("reflect")] = ALL_GLSL(Reflect);
104 fIntrinsicMap[String("refract")] = ALL_GLSL(Refract);
105 fIntrinsicMap[String("findLSB")] = ALL_GLSL(FindILsb);
106 fIntrinsicMap[String("findMSB")] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
107 fIntrinsicMap[String("dFdx")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400108 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700109 fIntrinsicMap[String("dFdy")] = SPECIAL(DFdy);
Chris Dalton09212192018-11-13 15:07:24 -0500110 fIntrinsicMap[String("fwidth")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFwidth,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400111 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400112 fIntrinsicMap[String("makeSampler2D")] = SPECIAL(SampledImage);
113
Ethan Nicholas13863662019-07-29 13:05:15 -0400114 fIntrinsicMap[String("sample")] = SPECIAL(Texture);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400115 fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
Greg Daniel64773e62016-11-22 09:44:03 -0500116
John Stilescc9ff002020-12-09 18:39:41 -0500117 fIntrinsicMap[String("floatBitsToInt")] = ALL_SPIRV(Bitcast);
118 fIntrinsicMap[String("floatBitsToUint")] = ALL_SPIRV(Bitcast);
119 fIntrinsicMap[String("intBitsToFloat")] = ALL_SPIRV(Bitcast);
120 fIntrinsicMap[String("uintBitsToFloat")] = ALL_SPIRV(Bitcast);
121
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400122 fIntrinsicMap[String("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400123 SpvOpUndef, SpvOpUndef, SpvOpAny);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400124 fIntrinsicMap[String("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400125 SpvOpUndef, SpvOpUndef, SpvOpAll);
Brian Osman540c13a2020-11-24 16:55:34 -0500126 fIntrinsicMap[String("not")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
127 SpvOpUndef, SpvOpUndef,
128 SpvOpLogicalNot);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400129 fIntrinsicMap[String("equal")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400130 SpvOpFOrdEqual, SpvOpIEqual,
131 SpvOpIEqual, SpvOpLogicalEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400132 fIntrinsicMap[String("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400133 SpvOpFOrdNotEqual, SpvOpINotEqual,
134 SpvOpINotEqual,
135 SpvOpLogicalNotEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400136 fIntrinsicMap[String("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500137 SpvOpFOrdLessThan, SpvOpSLessThan,
138 SpvOpULessThan, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400139 fIntrinsicMap[String("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500140 SpvOpFOrdLessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400141 SpvOpSLessThanEqual,
142 SpvOpULessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400143 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400144 fIntrinsicMap[String("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500145 SpvOpFOrdGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400146 SpvOpSGreaterThan,
147 SpvOpUGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400148 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400149 fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500150 SpvOpFOrdGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400151 SpvOpSGreaterThanEqual,
152 SpvOpUGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400153 SpvOpUndef);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400154 fIntrinsicMap[String("EmitVertex")] = ALL_SPIRV(EmitVertex);
155 fIntrinsicMap[String("EndPrimitive")] = ALL_SPIRV(EndPrimitive);
ethannicholasb3058bd2016-07-01 08:22:01 -0700156// interpolateAt* not yet supported...
157}
158
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400159void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700160 out.write((const char*) &word, sizeof(word));
ethannicholasb3058bd2016-07-01 08:22:01 -0700161}
162
ethannicholasd598f792016-07-25 10:08:54 -0700163static bool is_float(const Context& context, const Type& type) {
Ethan Nicholas0df21132018-07-10 09:37:51 -0400164 if (type.columns() > 1) {
ethannicholasd598f792016-07-25 10:08:54 -0700165 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700166 }
John Stiles123501f2020-12-09 10:08:13 -0500167 return type.isFloat();
ethannicholasb3058bd2016-07-01 08:22:01 -0700168}
169
ethannicholasd598f792016-07-25 10:08:54 -0700170static bool is_signed(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500171 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700172 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700173 }
John Stiles123501f2020-12-09 10:08:13 -0500174 return type.isSigned();
ethannicholasb3058bd2016-07-01 08:22:01 -0700175}
176
ethannicholasd598f792016-07-25 10:08:54 -0700177static bool is_unsigned(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_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700180 }
John Stiles123501f2020-12-09 10:08:13 -0500181 return type.isUnsigned();
ethannicholasb3058bd2016-07-01 08:22:01 -0700182}
183
ethannicholasd598f792016-07-25 10:08:54 -0700184static bool is_bool(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500185 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700186 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700187 }
John Stiles123501f2020-12-09 10:08:13 -0500188 return type.isBoolean();
ethannicholasb3058bd2016-07-01 08:22:01 -0700189}
190
ethannicholasd598f792016-07-25 10:08:54 -0700191static bool is_out(const Variable& var) {
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400192 return (var.modifiers().fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700193}
194
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400195void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400196 SkASSERT(opCode != SpvOpLoad || &out != &fConstantBuffer);
197 SkASSERT(opCode != SpvOpUndef);
ethannicholasb3058bd2016-07-01 08:22:01 -0700198 switch (opCode) {
199 case SpvOpReturn: // fall through
200 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700201 case SpvOpKill: // fall through
Ethan Nicholas7fb39362020-12-16 15:25:19 -0500202 case SpvOpSwitch: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700203 case SpvOpBranch: // fall through
204 case SpvOpBranchConditional:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400205 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700206 fCurrentBlock = 0;
207 break;
208 case SpvOpConstant: // fall through
209 case SpvOpConstantTrue: // fall through
210 case SpvOpConstantFalse: // fall through
211 case SpvOpConstantComposite: // fall through
212 case SpvOpTypeVoid: // fall through
213 case SpvOpTypeInt: // fall through
214 case SpvOpTypeFloat: // fall through
215 case SpvOpTypeBool: // fall through
216 case SpvOpTypeVector: // fall through
217 case SpvOpTypeMatrix: // fall through
218 case SpvOpTypeArray: // fall through
219 case SpvOpTypePointer: // fall through
220 case SpvOpTypeFunction: // fall through
221 case SpvOpTypeRuntimeArray: // fall through
222 case SpvOpTypeStruct: // fall through
223 case SpvOpTypeImage: // fall through
224 case SpvOpTypeSampledImage: // fall through
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400225 case SpvOpTypeSampler: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700226 case SpvOpVariable: // fall through
227 case SpvOpFunction: // fall through
228 case SpvOpFunctionParameter: // fall through
229 case SpvOpFunctionEnd: // fall through
230 case SpvOpExecutionMode: // fall through
231 case SpvOpMemoryModel: // fall through
232 case SpvOpCapability: // fall through
233 case SpvOpExtInstImport: // fall through
234 case SpvOpEntryPoint: // fall through
235 case SpvOpSource: // fall through
236 case SpvOpSourceExtension: // fall through
237 case SpvOpName: // fall through
238 case SpvOpMemberName: // fall through
239 case SpvOpDecorate: // fall through
240 case SpvOpMemberDecorate:
241 break;
242 default:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400243 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700244 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700245 this->writeWord((length << 16) | opCode, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700246}
247
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400248void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
Ethan Nicholas7fb39362020-12-16 15:25:19 -0500249 SkASSERT(!fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700250 fCurrentBlock = label;
251 this->writeInstruction(SpvOpLabel, label, out);
252}
253
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400254void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700255 this->writeOpCode(opCode, 1, out);
256}
257
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400258void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700259 this->writeOpCode(opCode, 2, out);
260 this->writeWord(word1, out);
261}
262
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700263void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputStream& out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400264 out.write(string, length);
ethannicholasb3058bd2016-07-01 08:22:01 -0700265 switch (length % 4) {
266 case 1:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500267 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400268 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700269 case 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500270 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400271 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700272 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500273 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700274 break;
275 default:
276 this->writeWord(0, out);
277 }
278}
279
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700280void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out) {
281 this->writeOpCode(opCode, 1 + (string.fLength + 4) / 4, out);
282 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700283}
284
285
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700286void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400287 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700288 this->writeOpCode(opCode, 2 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700289 this->writeWord(word1, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700290 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700291}
292
Greg Daniel64773e62016-11-22 09:44:03 -0500293void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700294 StringFragment string, OutputStream& out) {
295 this->writeOpCode(opCode, 3 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700296 this->writeWord(word1, out);
297 this->writeWord(word2, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700298 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700299}
300
Greg Daniel64773e62016-11-22 09:44:03 -0500301void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400302 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700303 this->writeOpCode(opCode, 3, out);
304 this->writeWord(word1, out);
305 this->writeWord(word2, out);
306}
307
Greg Daniel64773e62016-11-22 09:44:03 -0500308void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400309 int32_t word3, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700310 this->writeOpCode(opCode, 4, out);
311 this->writeWord(word1, out);
312 this->writeWord(word2, out);
313 this->writeWord(word3, out);
314}
315
Greg Daniel64773e62016-11-22 09:44:03 -0500316void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400317 int32_t word3, int32_t word4, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700318 this->writeOpCode(opCode, 5, out);
319 this->writeWord(word1, out);
320 this->writeWord(word2, out);
321 this->writeWord(word3, out);
322 this->writeWord(word4, out);
323}
324
Greg Daniel64773e62016-11-22 09:44:03 -0500325void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
326 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400327 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700328 this->writeOpCode(opCode, 6, out);
329 this->writeWord(word1, out);
330 this->writeWord(word2, out);
331 this->writeWord(word3, out);
332 this->writeWord(word4, out);
333 this->writeWord(word5, out);
334}
335
Greg Daniel64773e62016-11-22 09:44:03 -0500336void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700337 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400338 int32_t word6, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700339 this->writeOpCode(opCode, 7, out);
340 this->writeWord(word1, out);
341 this->writeWord(word2, out);
342 this->writeWord(word3, out);
343 this->writeWord(word4, out);
344 this->writeWord(word5, out);
345 this->writeWord(word6, out);
346}
347
Greg Daniel64773e62016-11-22 09:44:03 -0500348void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700349 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400350 int32_t word6, int32_t word7, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700351 this->writeOpCode(opCode, 8, out);
352 this->writeWord(word1, out);
353 this->writeWord(word2, out);
354 this->writeWord(word3, out);
355 this->writeWord(word4, out);
356 this->writeWord(word5, out);
357 this->writeWord(word6, out);
358 this->writeWord(word7, out);
359}
360
Greg Daniel64773e62016-11-22 09:44:03 -0500361void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700362 int32_t word3, int32_t word4, int32_t word5,
363 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400364 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700365 this->writeOpCode(opCode, 9, out);
366 this->writeWord(word1, out);
367 this->writeWord(word2, out);
368 this->writeWord(word3, out);
369 this->writeWord(word4, out);
370 this->writeWord(word5, out);
371 this->writeWord(word6, out);
372 this->writeWord(word7, out);
373 this->writeWord(word8, out);
374}
375
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400376void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700377 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
378 if (fCapabilities & bit) {
379 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
380 }
381 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400382 if (fProgram.fKind == Program::kGeometry_Kind) {
383 this->writeInstruction(SpvOpCapability, SpvCapabilityGeometry, out);
384 }
Ethan Nicholas81d15112018-07-13 12:48:50 -0400385 else {
386 this->writeInstruction(SpvOpCapability, SpvCapabilityShader, out);
387 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700388}
389
390SpvId SPIRVCodeGenerator::nextId() {
391 return fIdCount++;
392}
393
Ethan Nicholas19671772016-11-28 16:30:17 -0500394void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
395 SpvId resultId) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400396 this->writeInstruction(SpvOpName, resultId, String(type.name()).c_str(), fNameBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700397 // go ahead and write all of the field types, so we don't inadvertently write them while we're
398 // in the middle of writing the struct instruction
399 std::vector<SpvId> types;
400 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500401 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700402 }
403 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
404 this->writeWord(resultId, fConstantBuffer);
405 for (SpvId id : types) {
406 this->writeWord(id, fConstantBuffer);
407 }
408 size_t offset = 0;
409 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400410 const Type::Field& field = type.fields()[i];
John Stiles21f5f452020-11-30 09:57:59 -0500411 if (!MemoryLayout::LayoutIsSupported(*field.fType)) {
John Stiles0023c0c2020-11-16 13:32:18 -0500412 fErrors.error(type.fOffset, "type '" + field.fType->name() + "' is not permitted here");
413 return;
414 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400415 size_t size = memoryLayout.size(*field.fType);
416 size_t alignment = memoryLayout.alignment(*field.fType);
417 const Layout& fieldLayout = field.fModifiers.fLayout;
Ethan Nicholas19671772016-11-28 16:30:17 -0500418 if (fieldLayout.fOffset >= 0) {
Greg Danieldbd44c72017-01-24 15:12:12 -0500419 if (fieldLayout.fOffset < (int) offset) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700420 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400421 "offset of field '" + field.fName + "' must be at "
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500422 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -0500423 }
424 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700425 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400426 "offset of field '" + field.fName + "' must be a multiple"
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500427 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -0500428 }
429 offset = fieldLayout.fOffset;
430 } else {
431 size_t mod = offset % alignment;
432 if (mod) {
433 offset += alignment - mod;
434 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700435 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400436 this->writeInstruction(SpvOpMemberName, resultId, i, field.fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500437 this->writeLayout(fieldLayout, resultId, i);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400438 if (field.fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -0500439 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700440 (SpvId) offset, fDecorationBuffer);
441 }
John Stiles9aeed132020-11-24 17:36:06 -0500442 if (field.fType->isMatrix()) {
Greg Daniel64773e62016-11-22 09:44:03 -0500443 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -0700444 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500445 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400446 (SpvId) memoryLayout.stride(*field.fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800447 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700448 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400449 if (!field.fType->highPrecision()) {
450 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i,
451 SpvDecorationRelaxedPrecision, fDecorationBuffer);
452 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700453 offset += size;
John Stilesc0c51062020-12-03 17:16:29 -0500454 if ((field.fType->isArray() || field.fType->isStruct()) && offset % alignment != 0) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700455 offset += alignment - offset % alignment;
456 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700457 }
458}
459
Ethan Nicholase2c49992020-10-05 11:49:11 -0400460const Type& SPIRVCodeGenerator::getActualType(const Type& type) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500461 if (type.isFloat()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400462 return *fContext.fFloat_Type;
463 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500464 if (type.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400465 return *fContext.fInt_Type;
466 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500467 if (type.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400468 return *fContext.fUInt_Type;
469 }
John Stiles9aeed132020-11-24 17:36:06 -0500470 if (type.isMatrix() || type.isVector()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400471 if (type.componentType() == *fContext.fHalf_Type) {
472 return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
473 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400474 if (type.componentType() == *fContext.fShort_Type ||
475 type.componentType() == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400476 return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
477 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400478 if (type.componentType() == *fContext.fUShort_Type ||
479 type.componentType() == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400480 return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
481 }
482 }
483 return type;
484}
485
ethannicholasb3058bd2016-07-01 08:22:01 -0700486SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800487 return this->getType(type, fDefaultLayout);
488}
489
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400490SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400491 const Type& type = this->getActualType(rawType);
Jim Van Verthf3ec9832020-10-21 16:09:57 -0400492 String key = type.name();
John Stilesc0c51062020-12-03 17:16:29 -0500493 if (type.isStruct() || type.isArray()) {
Jim Van Verthf3ec9832020-10-21 16:09:57 -0400494 key += to_string((int)layout.fStd);
495 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800496 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700497 if (entry == fTypeMap.end()) {
498 SpvId result = this->nextId();
Ethan Nicholase6592142020-09-08 10:22:09 -0400499 switch (type.typeKind()) {
500 case Type::TypeKind::kScalar:
John Stiles4a7dc462020-11-25 11:08:08 -0500501 if (type.isBoolean()) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700502 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500503 } else if (type == *fContext.fInt_Type || type == *fContext.fShort_Type ||
504 type == *fContext.fIntLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700505 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500506 } else if (type == *fContext.fUInt_Type || type == *fContext.fUShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700507 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500508 } else if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type ||
509 type == *fContext.fFloatLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700510 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700511 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400512 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700513 }
514 break;
John Stilesfd41d872020-11-25 22:39:45 -0500515 case Type::TypeKind::kEnum:
516 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
517 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400518 case Type::TypeKind::kVector:
Greg Daniel64773e62016-11-22 09:44:03 -0500519 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800520 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700521 type.columns(), fConstantBuffer);
522 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400523 case Type::TypeKind::kMatrix:
Greg Daniel64773e62016-11-22 09:44:03 -0500524 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800525 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700526 type.columns(), fConstantBuffer);
527 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400528 case Type::TypeKind::kStruct:
ethannicholas8ac838d2016-11-22 08:39:36 -0800529 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700530 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400531 case Type::TypeKind::kArray: {
John Stiles21f5f452020-11-30 09:57:59 -0500532 if (!MemoryLayout::LayoutIsSupported(type)) {
533 fErrors.error(type.fOffset, "type '" + type.name() + "' is not permitted here");
534 return this->nextId();
535 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700536 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700537 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500538 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800539 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700540 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500541 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400542 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800543 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700544 } else {
John Stiles5570c512020-11-19 17:58:07 -0500545 // We shouldn't have any runtime-sized arrays right now
546 fErrors.error(type.fOffset, "runtime-sized arrays are not supported in SPIR-V");
Greg Daniel64773e62016-11-22 09:44:03 -0500547 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800548 this->getType(type.componentType(), layout),
549 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400550 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
551 (int32_t) layout.stride(type),
552 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700553 }
554 break;
555 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400556 case Type::TypeKind::kSampler: {
Greg Daniel64773e62016-11-22 09:44:03 -0500557 SpvId image = result;
558 if (SpvDimSubpassData != type.dimensions()) {
Stephen White792e2302019-08-09 13:33:51 -0400559 image = this->getType(type.textureType(), layout);
Greg Daniel64773e62016-11-22 09:44:03 -0500560 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400561 if (SpvDimBuffer == type.dimensions()) {
562 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
563 }
Greg Daniel64773e62016-11-22 09:44:03 -0500564 if (SpvDimSubpassData != type.dimensions()) {
565 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
566 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700567 break;
568 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400569 case Type::TypeKind::kSeparateSampler: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400570 this->writeInstruction(SpvOpTypeSampler, result, fConstantBuffer);
571 break;
572 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400573 case Type::TypeKind::kTexture: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400574 this->writeInstruction(SpvOpTypeImage, result,
575 this->getType(*fContext.fFloat_Type, layout),
John Stilesc0c51062020-12-03 17:16:29 -0500576 type.dimensions(), type.isDepth(), type.isArrayedTexture(),
Stephen White792e2302019-08-09 13:33:51 -0400577 type.isMultisampled(), type.isSampled() ? 1 : 2,
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400578 SpvImageFormatUnknown, fConstantBuffer);
579 fImageTypeMap[key] = result;
580 break;
581 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700582 default:
ethannicholasd598f792016-07-25 10:08:54 -0700583 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700584 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
585 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500586#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700587 ABORT("invalid type: %s", type.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500588#endif
ethannicholasb3058bd2016-07-01 08:22:01 -0700589 }
590 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800591 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700592 return result;
593 }
594 return entry->second;
595}
596
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400597SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400598 SkASSERT(type.typeKind() == Type::TypeKind::kSampler);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400599 this->getType(type);
600 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400601 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400602 return fImageTypeMap[key];
603}
604
ethannicholasd598f792016-07-25 10:08:54 -0700605SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400606 String key = to_string(this->getType(function.returnType())) + "(";
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400607 String separator;
Brian Osman5bf3e202020-10-13 10:34:18 -0400608 const std::vector<const Variable*>& parameters = function.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400609 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700610 key += separator;
611 separator = ", ";
Ethan Nicholased84b732020-10-08 11:45:44 -0400612 key += to_string(this->getType(parameters[i]->type()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700613 }
614 key += ")";
615 auto entry = fTypeMap.find(key);
616 if (entry == fTypeMap.end()) {
617 SpvId result = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -0400618 int32_t length = 3 + (int32_t) parameters.size();
619 SpvId returnType = this->getType(function.returnType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700620 std::vector<SpvId> parameterTypes;
Ethan Nicholased84b732020-10-08 11:45:44 -0400621 for (size_t i = 0; i < parameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500622 // glslang seems to treat all function arguments as pointers whether they need to be or
623 // not. I was initially puzzled by this until I ran bizarre failures with certain
624 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700625 // failure case:
626 //
627 // void sphere(float x) {
628 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500629 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700630 // void map() {
631 // sphere(1.0);
632 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500633 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700634 // void main() {
635 // for (int i = 0; i < 1; i++) {
636 // map();
637 // }
638 // }
639 //
Greg Daniel64773e62016-11-22 09:44:03 -0500640 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
641 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700642 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
643 // the spec makes this make sense.
644// if (is_out(function->fParameters[i])) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400645 parameterTypes.push_back(this->getPointerType(parameters[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -0700646 SpvStorageClassFunction));
647// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700648// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700649// }
650 }
651 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
652 this->writeWord(result, fConstantBuffer);
653 this->writeWord(returnType, fConstantBuffer);
654 for (SpvId id : parameterTypes) {
655 this->writeWord(id, fConstantBuffer);
656 }
657 fTypeMap[key] = result;
658 return result;
659 }
660 return entry->second;
661}
662
ethannicholas8ac838d2016-11-22 08:39:36 -0800663SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
664 return this->getPointerType(type, fDefaultLayout, storageClass);
665}
666
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400667SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700668 SpvStorageClass_ storageClass) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400669 const Type& type = this->getActualType(rawType);
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500670 String key = type.displayName() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700671 auto entry = fTypeMap.find(key);
672 if (entry == fTypeMap.end()) {
673 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500674 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700675 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700676 fTypeMap[key] = result;
677 return result;
678 }
679 return entry->second;
680}
681
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400682SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400683 switch (expr.kind()) {
684 case Expression::Kind::kBinary:
John Stiles81365af2020-08-18 09:24:00 -0400685 return this->writeBinaryExpression(expr.as<BinaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400686 case Expression::Kind::kBoolLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400687 return this->writeBoolLiteral(expr.as<BoolLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400688 case Expression::Kind::kConstructor:
John Stiles81365af2020-08-18 09:24:00 -0400689 return this->writeConstructor(expr.as<Constructor>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400690 case Expression::Kind::kIntLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400691 return this->writeIntLiteral(expr.as<IntLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400692 case Expression::Kind::kFieldAccess:
John Stiles81365af2020-08-18 09:24:00 -0400693 return this->writeFieldAccess(expr.as<FieldAccess>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400694 case Expression::Kind::kFloatLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400695 return this->writeFloatLiteral(expr.as<FloatLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400696 case Expression::Kind::kFunctionCall:
John Stiles81365af2020-08-18 09:24:00 -0400697 return this->writeFunctionCall(expr.as<FunctionCall>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400698 case Expression::Kind::kPrefix:
John Stiles81365af2020-08-18 09:24:00 -0400699 return this->writePrefixExpression(expr.as<PrefixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400700 case Expression::Kind::kPostfix:
John Stiles81365af2020-08-18 09:24:00 -0400701 return this->writePostfixExpression(expr.as<PostfixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400702 case Expression::Kind::kSwizzle:
John Stiles81365af2020-08-18 09:24:00 -0400703 return this->writeSwizzle(expr.as<Swizzle>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400704 case Expression::Kind::kVariableReference:
John Stiles81365af2020-08-18 09:24:00 -0400705 return this->writeVariableReference(expr.as<VariableReference>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400706 case Expression::Kind::kTernary:
John Stiles81365af2020-08-18 09:24:00 -0400707 return this->writeTernaryExpression(expr.as<TernaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400708 case Expression::Kind::kIndex:
John Stiles81365af2020-08-18 09:24:00 -0400709 return this->writeIndexExpression(expr.as<IndexExpression>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700710 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500711#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700712 ABORT("unsupported expression: %s", expr.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500713#endif
714 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700715 }
716 return -1;
717}
718
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400719SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400720 const FunctionDeclaration& function = c.function();
John Stiles8e3b6be2020-10-13 11:14:08 -0400721 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400722 auto intrinsic = fIntrinsicMap.find(function.name());
John Stiles93e661a2020-12-08 16:17:00 -0500723 if (intrinsic == fIntrinsicMap.end()) {
724 fErrors.error(c.fOffset, "unsupported intrinsic '" + function.description() + "'");
725 return -1;
726 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700727 int32_t intrinsicId;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400728 if (arguments.size() > 0) {
729 const Type& type = arguments[0]->type();
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400730 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
731 intrinsicId = std::get<1>(intrinsic->second);
732 } else if (is_signed(fContext, type)) {
733 intrinsicId = std::get<2>(intrinsic->second);
734 } else if (is_unsigned(fContext, type)) {
735 intrinsicId = std::get<3>(intrinsic->second);
736 } else if (is_bool(fContext, type)) {
737 intrinsicId = std::get<4>(intrinsic->second);
738 } else {
739 intrinsicId = std::get<1>(intrinsic->second);
740 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700741 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400742 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700743 }
744 switch (std::get<0>(intrinsic->second)) {
745 case kGLSL_STD_450_IntrinsicKind: {
746 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400747 std::vector<SpvId> argumentIds;
748 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400749 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400750 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400751 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400752 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400753 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700754 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400755 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400756 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700757 this->writeWord(result, out);
758 this->writeWord(fGLSLExtendedInstructions, out);
759 this->writeWord(intrinsicId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400760 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700761 this->writeWord(id, out);
762 }
763 return result;
764 }
765 case kSPIRV_IntrinsicKind: {
Brian Osman46787d52020-11-24 14:18:23 -0500766 // GLSL supports dot(float, float), but SPIR-V does not. Convert it to FMul
John Stiles9aeed132020-11-24 17:36:06 -0500767 if (intrinsicId == SpvOpDot && arguments[0]->type().isScalar()) {
Brian Osman46787d52020-11-24 14:18:23 -0500768 intrinsicId = SpvOpFMul;
769 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700770 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400771 std::vector<SpvId> argumentIds;
772 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400773 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400774 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400775 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400776 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400777 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700778 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400779 if (c.type() != *fContext.fVoid_Type) {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400780 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400781 this->writeWord(this->getType(c.type()), out);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400782 this->writeWord(result, out);
783 } else {
784 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
785 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400786 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700787 this->writeWord(id, out);
788 }
789 return result;
790 }
791 case kSpecial_IntrinsicKind:
792 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
793 default:
John Stiles93e661a2020-12-08 16:17:00 -0500794 fErrors.error(c.fOffset, "unsupported intrinsic '" + function.description() + "'");
795 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700796 }
797}
798
John Stiles8e3b6be2020-10-13 11:14:08 -0400799std::vector<SpvId> SPIRVCodeGenerator::vectorize(const ExpressionArray& args, OutputStream& out) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500800 int vectorSize = 0;
801 for (const auto& a : args) {
John Stiles9aeed132020-11-24 17:36:06 -0500802 if (a->type().isVector()) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500803 if (vectorSize) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400804 SkASSERT(a->type().columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500805 }
806 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400807 vectorSize = a->type().columns();
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500808 }
809 }
810 }
811 std::vector<SpvId> result;
John Stiles8e3b6be2020-10-13 11:14:08 -0400812 result.reserve(args.size());
Ethan Nicholas30d30222020-09-11 12:27:26 -0400813 for (const auto& arg : args) {
814 const Type& argType = arg->type();
815 SpvId raw = this->writeExpression(*arg, out);
John Stiles9aeed132020-11-24 17:36:06 -0500816 if (vectorSize && argType.isScalar()) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500817 SpvId vector = this->nextId();
818 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400819 this->writeWord(this->getType(argType.toCompound(fContext, vectorSize, 1)), out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500820 this->writeWord(vector, out);
821 for (int i = 0; i < vectorSize; i++) {
822 this->writeWord(raw, out);
823 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400824 this->writePrecisionModifier(argType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500825 result.push_back(vector);
826 } else {
827 result.push_back(raw);
828 }
829 }
830 return result;
831}
832
833void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
834 SpvId signedInst, SpvId unsignedInst,
835 const std::vector<SpvId>& args,
836 OutputStream& out) {
837 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
838 this->writeWord(this->getType(type), out);
839 this->writeWord(id, out);
840 this->writeWord(fGLSLExtendedInstructions, out);
841
842 if (is_float(fContext, type)) {
843 this->writeWord(floatInst, out);
844 } else if (is_signed(fContext, type)) {
845 this->writeWord(signedInst, out);
846 } else if (is_unsigned(fContext, type)) {
847 this->writeWord(unsignedInst, out);
848 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400849 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500850 }
851 for (SpvId a : args) {
852 this->writeWord(a, out);
853 }
854}
855
Greg Daniel64773e62016-11-22 09:44:03 -0500856SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400857 OutputStream& out) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400858 const ExpressionArray& arguments = c.arguments();
ethannicholasb3058bd2016-07-01 08:22:01 -0700859 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400860 const Type& callType = c.type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700861 switch (kind) {
862 case kAtan_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400863 std::vector<SpvId> argumentIds;
864 for (const std::unique_ptr<Expression>& arg : arguments) {
865 argumentIds.push_back(this->writeExpression(*arg, out));
ethannicholasb3058bd2016-07-01 08:22:01 -0700866 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400867 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400868 this->writeWord(this->getType(callType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700869 this->writeWord(result, out);
870 this->writeWord(fGLSLExtendedInstructions, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400871 this->writeWord(argumentIds.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
872 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700873 this->writeWord(id, out);
874 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400875 break;
876 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400877 case kSampledImage_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400878 SkASSERT(arguments.size() == 2);
879 SpvId img = this->writeExpression(*arguments[0], out);
880 SpvId sampler = this->writeExpression(*arguments[1], out);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400881 this->writeInstruction(SpvOpSampledImage,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400882 this->getType(callType),
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400883 result,
884 img,
885 sampler,
886 out);
887 break;
888 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400889 case kSubpassLoad_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400890 SpvId img = this->writeExpression(*arguments[0], out);
John Stiles8e3b6be2020-10-13 11:14:08 -0400891 ExpressionArray args;
John Stilesf4bda742020-10-14 16:57:41 -0400892 args.reserve_back(2);
John Stiles8e3b6be2020-10-13 11:14:08 -0400893 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
894 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
Ethan Nicholas30d30222020-09-11 12:27:26 -0400895 Constructor ctor(-1, fContext.fInt2_Type.get(), std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400896 SpvId coords = this->writeConstantVector(ctor);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400897 if (arguments.size() == 1) {
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400898 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400899 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400900 result,
901 img,
902 coords,
903 out);
904 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400905 SkASSERT(arguments.size() == 2);
906 SpvId sample = this->writeExpression(*arguments[1], out);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400907 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400908 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400909 result,
910 img,
911 coords,
912 SpvImageOperandsSampleMask,
913 sample,
914 out);
915 }
916 break;
917 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700918 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500919 SpvOp_ op = SpvOpImageSampleImplicitLod;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400920 const Type& arg1Type = arguments[1]->type();
921 switch (arguments[0]->type().dimensions()) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500922 case SpvDim1D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400923 if (arg1Type == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500924 op = SpvOpImageSampleProjImplicitLod;
925 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400926 SkASSERT(arg1Type == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500927 }
928 break;
929 case SpvDim2D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400930 if (arg1Type == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500931 op = SpvOpImageSampleProjImplicitLod;
932 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400933 SkASSERT(arg1Type == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500934 }
935 break;
936 case SpvDim3D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400937 if (arg1Type == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500938 op = SpvOpImageSampleProjImplicitLod;
939 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400940 SkASSERT(arg1Type == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500941 }
942 break;
943 case SpvDimCube: // fall through
944 case SpvDimRect: // fall through
945 case SpvDimBuffer: // fall through
946 case SpvDimSubpassData:
947 break;
948 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400949 SpvId type = this->getType(callType);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400950 SpvId sampler = this->writeExpression(*arguments[0], out);
951 SpvId uv = this->writeExpression(*arguments[1], out);
952 if (arguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500953 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700954 SpvImageOperandsBiasMask,
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400955 this->writeExpression(*arguments[2], out),
ethannicholasb3058bd2016-07-01 08:22:01 -0700956 out);
957 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400958 SkASSERT(arguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500959 if (fProgram.fSettings.fSharpenTextures) {
960 FloatLiteral lodBias(fContext, -1, -0.5);
961 this->writeInstruction(op, type, result, sampler, uv,
962 SpvImageOperandsBiasMask,
963 this->writeFloatLiteral(lodBias),
964 out);
965 } else {
966 this->writeInstruction(op, type, result, sampler, uv,
967 out);
968 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700969 }
970 break;
971 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500972 case kMod_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400973 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400974 SkASSERT(args.size() == 2);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400975 const Type& operandType = arguments[0]->type();
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500976 SpvOp_ op;
977 if (is_float(fContext, operandType)) {
978 op = SpvOpFMod;
979 } else if (is_signed(fContext, operandType)) {
980 op = SpvOpSMod;
981 } else if (is_unsigned(fContext, operandType)) {
982 op = SpvOpUMod;
983 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400984 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500985 return 0;
986 }
987 this->writeOpCode(op, 5, out);
988 this->writeWord(this->getType(operandType), out);
989 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500990 this->writeWord(args[0], out);
991 this->writeWord(args[1], out);
992 break;
993 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700994 case kDFdy_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400995 SpvId fn = this->writeExpression(*arguments[0], out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700996 this->writeOpCode(SpvOpDPdy, 4, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400997 this->writeWord(this->getType(callType), out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700998 this->writeWord(result, out);
999 this->writeWord(fn, out);
1000 if (fProgram.fSettings.fFlipY) {
1001 // Flipping Y also negates the Y derivatives.
1002 SpvId flipped = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001003 this->writeInstruction(SpvOpFNegate, this->getType(callType), flipped, result,
1004 out);
1005 this->writePrecisionModifier(callType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -07001006 return flipped;
1007 }
1008 break;
1009 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001010 case kClamp_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001011 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001012 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001013 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001014 GLSLstd450UClamp, args, out);
1015 break;
1016 }
1017 case kMax_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001018 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001019 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001020 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMax, GLSLstd450SMax,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001021 GLSLstd450UMax, args, out);
1022 break;
1023 }
1024 case kMin_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001025 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001026 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001027 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMin, GLSLstd450SMin,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001028 GLSLstd450UMin, args, out);
1029 break;
1030 }
1031 case kMix_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001032 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001033 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001034 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMix, SpvOpUndef,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001035 SpvOpUndef, args, out);
1036 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -05001037 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001038 case kSaturate_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001039 SkASSERT(arguments.size() == 1);
John Stiles8e3b6be2020-10-13 11:14:08 -04001040 ExpressionArray finalArgs;
John Stilesf4bda742020-10-14 16:57:41 -04001041 finalArgs.reserve_back(3);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001042 finalArgs.push_back(arguments[0]->clone());
John Stiles8e3b6be2020-10-13 11:14:08 -04001043 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1044 /*value=*/0));
1045 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1046 /*value=*/1));
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001047 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001048 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001049 GLSLstd450UClamp, spvArgs, out);
1050 break;
1051 }
Brian Osman6ba3be12020-11-13 16:32:52 -05001052 case kSmoothStep_SpecialIntrinsic: {
1053 std::vector<SpvId> args = this->vectorize(arguments, out);
1054 SkASSERT(args.size() == 3);
1055 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450SmoothStep, SpvOpUndef,
1056 SpvOpUndef, args, out);
1057 break;
1058 }
1059 case kStep_SpecialIntrinsic: {
1060 std::vector<SpvId> args = this->vectorize(arguments, out);
1061 SkASSERT(args.size() == 2);
1062 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450Step, SpvOpUndef,
1063 SpvOpUndef, args, out);
1064 break;
1065 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001066 }
1067 return result;
1068}
1069
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001070SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001071 const FunctionDeclaration& function = c.function();
John Stiles8e3b6be2020-10-13 11:14:08 -04001072 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001073 const auto& entry = fFunctionMap.find(&function);
ethannicholasb3058bd2016-07-01 08:22:01 -07001074 if (entry == fFunctionMap.end()) {
1075 return this->writeIntrinsicCall(c, out);
1076 }
1077 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001078 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001079 std::vector<SpvId> argumentIds;
1080 for (size_t i = 0; i < arguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001081 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001082 // passed directly
1083 SpvId tmpVar;
1084 // if we need a temporary var to store this argument, this is the value to store in the var
1085 SpvId tmpValueId;
Ethan Nicholased84b732020-10-08 11:45:44 -04001086 if (is_out(*function.parameters()[i])) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001087 std::unique_ptr<LValue> lv = this->getLValue(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001088 SpvId ptr = lv->getPointer();
1089 if (ptr) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001090 argumentIds.push_back(ptr);
ethannicholasb3058bd2016-07-01 08:22:01 -07001091 continue;
1092 } else {
1093 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1094 // copy it into a temp, call the function, read the value out of the temp, and then
1095 // update the lvalue.
1096 tmpValueId = lv->load(out);
1097 tmpVar = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001098 lvalues.push_back(std::make_tuple(tmpVar, &arguments[i]->type(), std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001099 }
1100 } else {
1101 // see getFunctionType for an explanation of why we're always using pointer parameters
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001102 tmpValueId = this->writeExpression(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001103 tmpVar = this->nextId();
1104 }
Greg Daniel64773e62016-11-22 09:44:03 -05001105 this->writeInstruction(SpvOpVariable,
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001106 this->getPointerType(arguments[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001107 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001108 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001109 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001110 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001111 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001112 argumentIds.push_back(tmpVar);
ethannicholasb3058bd2016-07-01 08:22:01 -07001113 }
1114 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001115 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001116 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001117 this->writeWord(result, out);
1118 this->writeWord(entry->second, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001119 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001120 this->writeWord(id, out);
1121 }
1122 // now that the call is complete, we may need to update some lvalues with the new values of out
1123 // arguments
1124 for (const auto& tuple : lvalues) {
1125 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001126 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1127 out);
1128 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001129 std::get<2>(tuple)->store(load, out);
1130 }
1131 return result;
1132}
1133
ethannicholasf789b382016-08-03 12:43:36 -07001134SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001135 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001136 SkASSERT(type.isVector() && c.isCompileTimeConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001137 SpvId result = this->nextId();
1138 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001139 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1140 arguments.push_back(this->writeExpression(*arg, fConstantBuffer));
ethannicholasb3058bd2016-07-01 08:22:01 -07001141 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001142 SpvId typeId = this->getType(type);
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001143 if (c.arguments().size() == 1) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001144 // with a single argument, a vector will have all of its entries equal to the argument
Ethan Nicholas30d30222020-09-11 12:27:26 -04001145 this->writeOpCode(SpvOpConstantComposite, 3 + type.columns(), fConstantBuffer);
1146 this->writeWord(typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001147 this->writeWord(result, fConstantBuffer);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001148 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001149 this->writeWord(arguments[0], fConstantBuffer);
1150 }
1151 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001152 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.arguments().size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001153 fConstantBuffer);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001154 this->writeWord(typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001155 this->writeWord(result, fConstantBuffer);
1156 for (SpvId id : arguments) {
1157 this->writeWord(id, fConstantBuffer);
1158 }
1159 }
1160 return result;
1161}
1162
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001163SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001164 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001165 SkASSERT(c.arguments().size() == 1);
1166 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001167 SkASSERT(constructorType.isFloat());
1168 SkASSERT(argType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001169 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001170 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001171 if (argType.isSigned()) {
1172 this->writeInstruction(SpvOpConvertSToF, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001173 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001174 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001175 SkASSERT(argType.isUnsigned());
1176 this->writeInstruction(SpvOpConvertUToF, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001177 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001178 }
1179 return result;
1180}
1181
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001182SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001183 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001184 SkASSERT(c.arguments().size() == 1);
1185 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001186 SkASSERT(constructorType.isSigned());
1187 SkASSERT(argType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001188 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001189 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001190 if (argType.isFloat()) {
1191 this->writeInstruction(SpvOpConvertFToS, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001192 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001193 }
1194 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001195 SkASSERT(argType.isUnsigned());
1196 this->writeInstruction(SpvOpBitcast, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001197 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001198 }
1199 return result;
1200}
1201
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001202SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001203 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001204 SkASSERT(c.arguments().size() == 1);
1205 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001206 SkASSERT(constructorType.isUnsigned());
1207 SkASSERT(argType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001208 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001209 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001210 if (argType.isFloat()) {
1211 this->writeInstruction(SpvOpConvertFToU, this->getType(constructorType), result, parameter,
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001212 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001213 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001214 SkASSERT(argType.isSigned());
1215 this->writeInstruction(SpvOpBitcast, this->getType(constructorType), result, parameter,
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001216 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001217 }
1218 return result;
1219}
1220
Ethan Nicholas84645e32017-02-09 13:57:14 -05001221void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001222 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001223 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001224 SpvId zeroId = this->writeFloatLiteral(zero);
1225 std::vector<SpvId> columnIds;
1226 for (int column = 0; column < type.columns(); column++) {
1227 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1228 out);
1229 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1230 out);
1231 SpvId columnId = this->nextId();
1232 this->writeWord(columnId, out);
1233 columnIds.push_back(columnId);
1234 for (int row = 0; row < type.columns(); row++) {
1235 this->writeWord(row == column ? diagonal : zeroId, out);
1236 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001237 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001238 }
1239 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1240 out);
1241 this->writeWord(this->getType(type), out);
1242 this->writeWord(id, out);
John Stilesf621e232020-08-25 13:33:02 -04001243 for (SpvId columnId : columnIds) {
1244 this->writeWord(columnId, out);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001245 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001246 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001247}
1248
1249void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001250 const Type& dstType, OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05001251 SkASSERT(srcType.isMatrix());
1252 SkASSERT(dstType.isMatrix());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001253 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001254 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1255 srcType.rows(),
1256 1));
1257 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1258 dstType.rows(),
1259 1));
1260 SpvId zeroId;
1261 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001262 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001263 zeroId = this->writeFloatLiteral(zero);
1264 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001265 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001266 zeroId = this->writeIntLiteral(zero);
1267 } else {
1268 ABORT("unsupported matrix component type");
1269 }
1270 SpvId zeroColumn = 0;
1271 SpvId columns[4];
1272 for (int i = 0; i < dstType.columns(); i++) {
1273 if (i < srcType.columns()) {
1274 // we're still inside the src matrix, copy the column
1275 SpvId srcColumn = this->nextId();
1276 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001277 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001278 SpvId dstColumn;
1279 if (srcType.rows() == dstType.rows()) {
1280 // columns are equal size, don't need to do anything
1281 dstColumn = srcColumn;
1282 }
1283 else if (dstType.rows() > srcType.rows()) {
1284 // dst column is bigger, need to zero-pad it
1285 dstColumn = this->nextId();
1286 int delta = dstType.rows() - srcType.rows();
1287 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1288 this->writeWord(dstColumnType, out);
1289 this->writeWord(dstColumn, out);
1290 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001291 for (int j = 0; j < delta; ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001292 this->writeWord(zeroId, out);
1293 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001294 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001295 }
1296 else {
1297 // dst column is smaller, need to swizzle the src column
1298 dstColumn = this->nextId();
1299 int count = dstType.rows();
1300 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1301 this->writeWord(dstColumnType, out);
1302 this->writeWord(dstColumn, out);
1303 this->writeWord(srcColumn, out);
1304 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001305 for (int j = 0; j < count; j++) {
1306 this->writeWord(j, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001307 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001308 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001309 }
1310 columns[i] = dstColumn;
1311 } else {
1312 // we're past the end of the src matrix, need a vector of zeroes
1313 if (!zeroColumn) {
1314 zeroColumn = this->nextId();
1315 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1316 this->writeWord(dstColumnType, out);
1317 this->writeWord(zeroColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001318 for (int j = 0; j < dstType.rows(); ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001319 this->writeWord(zeroId, out);
1320 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001321 this->writePrecisionModifier(dstType, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001322 }
1323 columns[i] = zeroColumn;
1324 }
1325 }
1326 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1327 this->writeWord(this->getType(dstType), out);
1328 this->writeWord(id, out);
1329 for (int i = 0; i < dstType.columns(); i++) {
1330 this->writeWord(columns[i], out);
1331 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001332 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001333}
1334
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001335void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1336 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001337 std::vector<SpvId>* columnIds,
1338 int* currentCount, int rows, SpvId entry,
1339 OutputStream& out) {
1340 SkASSERT(*currentCount < rows);
1341 ++(*currentCount);
1342 currentColumn->push_back(entry);
1343 if (*currentCount == rows) {
1344 *currentCount = 0;
1345 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1346 this->writeWord(columnType, out);
1347 SpvId columnId = this->nextId();
1348 this->writeWord(columnId, out);
1349 columnIds->push_back(columnId);
1350 for (SpvId id : *currentColumn) {
1351 this->writeWord(id, out);
1352 }
1353 currentColumn->clear();
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001354 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001355 }
1356}
1357
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001358SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001359 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001360 SkASSERT(type.isMatrix());
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001361 SkASSERT(c.arguments().size() > 0);
1362 const Type& arg0Type = c.arguments()[0]->type();
ethannicholasb3058bd2016-07-01 08:22:01 -07001363 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1364 // an instruction
1365 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001366 for (size_t i = 0; i < c.arguments().size(); i++) {
1367 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001368 }
1369 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001370 int rows = type.rows();
1371 int columns = type.columns();
John Stiles9aeed132020-11-24 17:36:06 -05001372 if (arguments.size() == 1 && arg0Type.isScalar()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001373 this->writeUniformScaleMatrix(result, arguments[0], type, out);
John Stiles9aeed132020-11-24 17:36:06 -05001374 } else if (arguments.size() == 1 && arg0Type.isMatrix()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001375 this->writeMatrixCopy(result, arguments[0], arg0Type, type, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001376 } else if (arguments.size() == 1 &&
John Stiles9aeed132020-11-24 17:36:06 -05001377 arg0Type.isVector()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001378 SkASSERT(type.rows() == 2 && type.columns() == 2);
1379 SkASSERT(arg0Type.columns() == 4);
1380 SpvId componentType = this->getType(type.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001381 SpvId v[4];
1382 for (int i = 0; i < 4; ++i) {
1383 v[i] = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001384 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i,
1385 out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001386 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001387 SpvId columnType = this->getType(type.componentType().toCompound(fContext, 2, 1));
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001388 SpvId column1 = this->nextId();
1389 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1390 SpvId column2 = this->nextId();
1391 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001392 this->writeInstruction(SpvOpCompositeConstruct, this->getType(type), result, column1,
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001393 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001394 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001395 SpvId columnType = this->getType(type.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001396 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001397 // ids of vectors and scalars we have written to the current column so far
1398 std::vector<SpvId> currentColumn;
1399 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001400 int currentCount = 0;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001401 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001402 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001403 const Type& argType = c.arguments()[i]->type();
John Stiles9aeed132020-11-24 17:36:06 -05001404 if (currentCount == 0 && argType.isVector() &&
Ethan Nicholas30d30222020-09-11 12:27:26 -04001405 argType.columns() == type.rows()) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001406 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001407 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001408 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001409 if (argType.columns() == 1) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001410 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1411 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001412 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001413 SpvId componentType = this->getType(argType.componentType());
1414 for (int j = 0; j < argType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001415 SpvId swizzle = this->nextId();
1416 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1417 arguments[i], j, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001418 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1419 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001420 }
1421 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001422 }
1423 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001424 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001425 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001426 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001427 this->writeWord(result, out);
1428 for (SpvId id : columnIds) {
1429 this->writeWord(id, out);
1430 }
1431 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001432 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001433 return result;
1434}
1435
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001436SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001437 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001438 SkASSERT(type.isVector());
Brian Osmanb6b95732020-06-30 11:44:27 -04001439 if (c.isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001440 return this->writeConstantVector(c);
1441 }
1442 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1443 // an instruction
1444 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001445 for (size_t i = 0; i < c.arguments().size(); i++) {
1446 const Type& argType = c.arguments()[i]->type();
John Stiles9aeed132020-11-24 17:36:06 -05001447 if (argType.isVector()) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001448 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1449 // extract the components and convert them in that case manually. On top of that,
1450 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1451 // doesn't handle vector arguments at all, so we always extract vector components and
1452 // pass them into OpCreateComposite individually.
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001453 SpvId vec = this->writeExpression(*c.arguments()[i], out);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001454 SpvOp_ op = SpvOpUndef;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001455 const Type& src = argType.componentType();
1456 const Type& dst = type.componentType();
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001457 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1458 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001459 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001460 return vec;
1461 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001462 } else if (src == *fContext.fInt_Type ||
1463 src == *fContext.fShort_Type ||
1464 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001465 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001466 } else if (src == *fContext.fUInt_Type ||
1467 src == *fContext.fUShort_Type ||
1468 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001469 op = SpvOpConvertUToF;
1470 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001471 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001472 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001473 } else if (dst == *fContext.fInt_Type ||
1474 dst == *fContext.fShort_Type ||
1475 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001476 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1477 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001478 } else if (src == *fContext.fInt_Type ||
1479 src == *fContext.fShort_Type ||
1480 src == *fContext.fByte_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001481 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001482 return vec;
1483 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001484 } else if (src == *fContext.fUInt_Type ||
1485 src == *fContext.fUShort_Type ||
1486 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001487 op = SpvOpBitcast;
1488 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001489 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001490 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001491 } else if (dst == *fContext.fUInt_Type ||
1492 dst == *fContext.fUShort_Type ||
1493 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001494 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1495 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001496 } else if (src == *fContext.fInt_Type ||
1497 src == *fContext.fShort_Type ||
1498 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001499 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001500 } else if (src == *fContext.fUInt_Type ||
1501 src == *fContext.fUShort_Type ||
1502 src == *fContext.fUByte_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001503 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001504 return vec;
1505 }
1506 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001507 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001508 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001509 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001510 for (int j = 0; j < argType.columns(); j++) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001511 SpvId swizzle = this->nextId();
1512 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1513 out);
1514 if (op != SpvOpUndef) {
1515 SpvId cast = this->nextId();
1516 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1517 arguments.push_back(cast);
1518 } else {
1519 arguments.push_back(swizzle);
1520 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001521 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001522 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001523 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001524 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001525 }
1526 SpvId result = this->nextId();
John Stiles9aeed132020-11-24 17:36:06 -05001527 if (arguments.size() == 1 && c.arguments()[0]->type().isScalar()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001528 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(), out);
1529 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001530 this->writeWord(result, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001531 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001532 this->writeWord(arguments[0], out);
1533 }
1534 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001535 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001536 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001537 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001538 this->writeWord(result, out);
1539 for (SpvId id : arguments) {
1540 this->writeWord(id, out);
1541 }
1542 }
1543 return result;
1544}
1545
Ethan Nicholasbd553222017-07-18 15:54:59 -04001546SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001547 const Type& type = c.type();
John Stilesc0c51062020-12-03 17:16:29 -05001548 SkASSERT(type.isArray());
Ethan Nicholasbd553222017-07-18 15:54:59 -04001549 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1550 // an instruction
1551 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001552 for (size_t i = 0; i < c.arguments().size(); i++) {
1553 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholasbd553222017-07-18 15:54:59 -04001554 }
1555 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001556 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.arguments().size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001557 this->writeWord(this->getType(type), out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001558 this->writeWord(result, out);
1559 for (SpvId id : arguments) {
1560 this->writeWord(id, out);
1561 }
1562 return result;
1563}
1564
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001565SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001566 const Type& type = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001567 if (c.arguments().size() == 1 &&
1568 this->getActualType(type) == this->getActualType(c.arguments()[0]->type())) {
1569 return this->writeExpression(*c.arguments()[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001570 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001571 if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001572 return this->writeFloatConstructor(c, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001573 } else if (type == *fContext.fInt_Type ||
1574 type == *fContext.fShort_Type ||
1575 type == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001576 return this->writeIntConstructor(c, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001577 } else if (type == *fContext.fUInt_Type ||
1578 type == *fContext.fUShort_Type ||
1579 type == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001580 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001581 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001582 switch (type.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001583 case Type::TypeKind::kVector:
ethannicholasb3058bd2016-07-01 08:22:01 -07001584 return this->writeVectorConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001585 case Type::TypeKind::kMatrix:
ethannicholasb3058bd2016-07-01 08:22:01 -07001586 return this->writeMatrixConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001587 case Type::TypeKind::kArray:
Ethan Nicholasbd553222017-07-18 15:54:59 -04001588 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001589 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001590#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07001591 ABORT("unsupported constructor: %s", c.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001592#endif
1593 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001594 }
1595}
1596
1597SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1598 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001599 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001600 return SpvStorageClassInput;
1601 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001602 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001603 return SpvStorageClassOutput;
1604 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001605 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001606 return SpvStorageClassPushConstant;
1607 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001608 return SpvStorageClassUniform;
1609 } else {
1610 return SpvStorageClassFunction;
1611 }
1612}
1613
ethannicholasf789b382016-08-03 12:43:36 -07001614SpvStorageClass_ get_storage_class(const Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001615 switch (expr.kind()) {
1616 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -04001617 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001618 if (var.storage() != Variable::Storage::kGlobal) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001619 return SpvStorageClassFunction;
1620 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001621 SpvStorageClass_ result = get_storage_class(var.modifiers());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001622 if (result == SpvStorageClassFunction) {
1623 result = SpvStorageClassPrivate;
1624 }
1625 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001626 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001627 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001628 return get_storage_class(*expr.as<FieldAccess>().base());
Ethan Nicholase6592142020-09-08 10:22:09 -04001629 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001630 return get_storage_class(*expr.as<IndexExpression>().base());
ethannicholasb3058bd2016-07-01 08:22:01 -07001631 default:
1632 return SpvStorageClassFunction;
1633 }
1634}
1635
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001636std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001637 std::vector<SpvId> chain;
Ethan Nicholase6592142020-09-08 10:22:09 -04001638 switch (expr.kind()) {
1639 case Expression::Kind::kIndex: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001640 IndexExpression& indexExpr = (IndexExpression&) expr;
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001641 chain = this->getAccessChain(*indexExpr.base(), out);
1642 chain.push_back(this->writeExpression(*indexExpr.index(), out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001643 break;
1644 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001645 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001646 FieldAccess& fieldExpr = (FieldAccess&) expr;
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001647 chain = this->getAccessChain(*fieldExpr.base(), out);
1648 IntLiteral index(fContext, -1, fieldExpr.fieldIndex());
ethannicholasb3058bd2016-07-01 08:22:01 -07001649 chain.push_back(this->writeIntLiteral(index));
1650 break;
1651 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001652 default: {
1653 SpvId id = this->getLValue(expr, out)->getPointer();
1654 SkASSERT(id != 0);
1655 chain.push_back(id);
1656 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001657 }
1658 return chain;
1659}
1660
1661class PointerLValue : public SPIRVCodeGenerator::LValue {
1662public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001663 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1664 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001665 : fGen(gen)
1666 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001667 , fType(type)
1668 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001669
John Stiles1cf2c8d2020-08-13 22:58:04 -04001670 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001671 return fPointer;
1672 }
1673
John Stiles1cf2c8d2020-08-13 22:58:04 -04001674 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001675 SpvId result = fGen.nextId();
1676 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001677 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001678 return result;
1679 }
1680
John Stiles1cf2c8d2020-08-13 22:58:04 -04001681 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001682 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1683 }
1684
1685private:
1686 SPIRVCodeGenerator& fGen;
1687 const SpvId fPointer;
1688 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001689 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001690};
1691
1692class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1693public:
John Stiles750109b2020-10-30 13:45:46 -04001694 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const ComponentArray& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001695 const Type& baseType, const Type& swizzleType,
1696 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001697 : fGen(gen)
1698 , fVecPointer(vecPointer)
1699 , fComponents(components)
1700 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001701 , fSwizzleType(swizzleType)
1702 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001703
John Stiles1cf2c8d2020-08-13 22:58:04 -04001704 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001705 return 0;
1706 }
1707
John Stiles1cf2c8d2020-08-13 22:58:04 -04001708 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001709 SpvId base = fGen.nextId();
1710 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001711 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001712 SpvId result = fGen.nextId();
1713 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1714 fGen.writeWord(fGen.getType(fSwizzleType), out);
1715 fGen.writeWord(result, out);
1716 fGen.writeWord(base, out);
1717 fGen.writeWord(base, out);
1718 for (int component : fComponents) {
1719 fGen.writeWord(component, out);
1720 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001721 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001722 return result;
1723 }
1724
John Stiles1cf2c8d2020-08-13 22:58:04 -04001725 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001726 // use OpVectorShuffle to mix and match the vector components. We effectively create
1727 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001728 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001729 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001730 // float3L = ...;
1731 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001732 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001733 // 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 -07001734 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1735 // (3, 1, 4).
1736 SpvId base = fGen.nextId();
1737 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1738 SpvId shuffle = fGen.nextId();
1739 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1740 fGen.writeWord(fGen.getType(fBaseType), out);
1741 fGen.writeWord(shuffle, out);
1742 fGen.writeWord(base, out);
1743 fGen.writeWord(value, out);
1744 for (int i = 0; i < fBaseType.columns(); i++) {
1745 // current offset into the virtual vector, defaults to pulling the unmodified
1746 // value from the left side
1747 int offset = i;
1748 // check to see if we are writing this component
1749 for (size_t j = 0; j < fComponents.size(); j++) {
1750 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001751 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001752 // the correct component of the right side instead of preserving the
1753 // value from the left
1754 offset = (int) (j + fBaseType.columns());
1755 break;
1756 }
1757 }
1758 fGen.writeWord(offset, out);
1759 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001760 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001761 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1762 }
1763
1764private:
1765 SPIRVCodeGenerator& fGen;
1766 const SpvId fVecPointer;
John Stiles750109b2020-10-30 13:45:46 -04001767 const ComponentArray& fComponents;
ethannicholasb3058bd2016-07-01 08:22:01 -07001768 const Type& fBaseType;
1769 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001770 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001771};
1772
Greg Daniel64773e62016-11-22 09:44:03 -05001773std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001774 OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001775 const Type& type = expr.type();
1776 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
Ethan Nicholase6592142020-09-08 10:22:09 -04001777 switch (expr.kind()) {
1778 case Expression::Kind::kVariableReference: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001779 SpvId typeId;
Ethan Nicholas78686922020-10-08 06:46:27 -04001780 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001781 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
John Stilesad2d4942020-12-11 16:55:58 -05001782 typeId = this->getType(*Type::MakeArrayType("sk_in", var.type().componentType(),
1783 fSkInCount));
Ethan Nicholas5226b772018-05-03 16:20:41 -04001784 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001785 typeId = this->getType(type);
Ethan Nicholas5226b772018-05-03 16:20:41 -04001786 }
ethannicholasd598f792016-07-25 10:08:54 -07001787 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001788 SkASSERT(entry != fVariableMap.end());
John Stiles5570c512020-11-19 17:58:07 -05001789 return std::make_unique<PointerLValue>(*this, entry->second, typeId, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001790 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001791 case Expression::Kind::kIndex: // fall through
1792 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001793 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1794 SpvId member = this->nextId();
1795 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001796 this->writeWord(this->getPointerType(type, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001797 this->writeWord(member, out);
1798 for (SpvId idx : chain) {
1799 this->writeWord(idx, out);
1800 }
John Stiles5570c512020-11-19 17:58:07 -05001801 return std::make_unique<PointerLValue>(*this, member, this->getType(type), precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001802 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001803 case Expression::Kind::kSwizzle: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001804 Swizzle& swizzle = (Swizzle&) expr;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001805 size_t count = swizzle.components().size();
1806 SpvId base = this->getLValue(*swizzle.base(), out)->getPointer();
John Stiles5570c512020-11-19 17:58:07 -05001807 if (!base) {
1808 fErrors.error(swizzle.fOffset, "unable to retrieve lvalue from swizzle");
1809 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001810 if (count == 1) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001811 IntLiteral index(fContext, -1, swizzle.components()[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001812 SpvId member = this->nextId();
1813 this->writeInstruction(SpvOpAccessChain,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001814 this->getPointerType(type,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001815 get_storage_class(*swizzle.base())),
Greg Daniel64773e62016-11-22 09:44:03 -05001816 member,
1817 base,
1818 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001819 out);
John Stiles5570c512020-11-19 17:58:07 -05001820 return std::make_unique<PointerLValue>(*this, member, this->getType(type),
1821 precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001822 } else {
John Stiles5570c512020-11-19 17:58:07 -05001823 return std::make_unique<SwizzleLValue>(*this, base, swizzle.components(),
1824 swizzle.base()->type(), type, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001825 }
1826 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001827 case Expression::Kind::kTernary: {
Ethan Nicholasa583b812018-01-18 13:32:11 -05001828 TernaryExpression& t = (TernaryExpression&) expr;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001829 SpvId test = this->writeExpression(*t.test(), out);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001830 SpvId end = this->nextId();
1831 SpvId ifTrueLabel = this->nextId();
1832 SpvId ifFalseLabel = this->nextId();
1833 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1834 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1835 this->writeLabel(ifTrueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04001836 SpvId ifTrue = this->getLValue(*t.ifTrue(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001837 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001838 this->writeInstruction(SpvOpBranch, end, out);
1839 ifTrueLabel = fCurrentBlock;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001840 SpvId ifFalse = this->getLValue(*t.ifFalse(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001841 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001842 ifFalseLabel = fCurrentBlock;
1843 this->writeInstruction(SpvOpBranch, end, out);
1844 SpvId result = this->nextId();
1845 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1846 ifTrueLabel, ifFalse, ifFalseLabel, out);
John Stiles5570c512020-11-19 17:58:07 -05001847 return std::make_unique<PointerLValue>(*this, result, this->getType(type), precision);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001848 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001849 default: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001850 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001851 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001852 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1853 // caught by IRGenerator
1854 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001855 SpvId pointerType = this->getPointerType(type, SpvStorageClassFunction);
1856 this->writeInstruction(SpvOpVariable, pointerType, result, SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001857 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001858 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
John Stiles5570c512020-11-19 17:58:07 -05001859 return std::make_unique<PointerLValue>(*this, result, this->getType(type), precision);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001860 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001861 }
1862}
1863
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001864SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001865 SpvId result = this->nextId();
Ethan Nicholas78686922020-10-08 06:46:27 -04001866 auto entry = fVariableMap.find(ref.variable());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001867 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001868 SpvId var = entry->second;
Ethan Nicholas78686922020-10-08 06:46:27 -04001869 this->writeInstruction(SpvOpLoad, this->getType(ref.variable()->type()), result, var, out);
1870 this->writePrecisionModifier(ref.variable()->type(), result);
1871 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
Brian Osmane38bedd2020-12-21 11:51:54 -05001872 fProgram.fSettings.fFlipY) {
Greg Daniela85e4bf2020-06-17 16:32:45 -04001873 // The x component never changes, so just grab it
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001874 SpvId xId = this->nextId();
1875 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1876 result, 0, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001877
1878 // Calculate the y component which may need to be flipped
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001879 SpvId rawYId = this->nextId();
1880 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1881 result, 1, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001882 SpvId flippedYId = 0;
1883 if (fProgram.fSettings.fFlipY) {
1884 // need to remap to a top-left coordinate system
1885 if (fRTHeightStructId == (SpvId)-1) {
1886 // height variable hasn't been written yet
Greg Daniela85e4bf2020-06-17 16:32:45 -04001887 SkASSERT(fRTHeightFieldIndex == (SpvId)-1);
1888 std::vector<Type::Field> fields;
John Stiles5570c512020-11-19 17:58:07 -05001889 if (fProgram.fSettings.fRTHeightOffset < 0) {
1890 fErrors.error(ref.fOffset, "RTHeightOffset is negative");
1891 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001892 fields.emplace_back(
1893 Modifiers(Layout(0, -1, fProgram.fSettings.fRTHeightOffset, -1, -1, -1, -1,
1894 -1, Layout::Format::kUnspecified,
1895 Layout::kUnspecified_Primitive, 1, -1, "", "",
1896 Layout::kNo_Key, Layout::CType::kDefault),
1897 0),
1898 SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1899 StringFragment name("sksl_synthetic_uniforms");
John Stilesad2d4942020-12-11 16:55:58 -05001900 std::unique_ptr<Type> intfStruct = Type::MakeStructType(/*offset=*/-1, name,
1901 fields);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001902 int binding = fProgram.fSettings.fRTHeightBinding;
John Stiles5570c512020-11-19 17:58:07 -05001903 if (binding == -1) {
1904 fErrors.error(ref.fOffset, "layout(binding=...) is required in SPIR-V");
1905 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001906 int set = fProgram.fSettings.fRTHeightSet;
John Stiles5570c512020-11-19 17:58:07 -05001907 if (set == -1) {
1908 fErrors.error(ref.fOffset, "layout(set=...) is required in SPIR-V");
1909 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001910 Layout layout(0, -1, -1, binding, -1, set, -1, -1, Layout::Format::kUnspecified,
1911 Layout::kUnspecified_Primitive, -1, -1, "", "", Layout::kNo_Key,
1912 Layout::CType::kDefault);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001913 Modifiers modifiers(layout, Modifiers::kUniform_Flag);
John Stiles3ae071e2020-08-05 15:29:29 -04001914 const Variable* intfVar = fSynthetics.takeOwnershipOfSymbol(
1915 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -05001916 fProgram.fModifiers->addToPool(modifiers),
John Stiles3ae071e2020-08-05 15:29:29 -04001917 name,
John Stilesad2d4942020-12-11 16:55:58 -05001918 intfStruct.get(),
Brian Osman3887a012020-09-30 13:22:27 -04001919 /*builtin=*/false,
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001920 Variable::Storage::kGlobal));
John Stilesd39aec02020-12-03 10:42:26 -05001921 InterfaceBlock intf(/*offset=*/-1, intfVar, name,
1922 /*instanceName=*/"", /*arraySize=*/0,
John Stiles7c3515b2020-10-16 18:38:39 -04001923 std::make_shared<SymbolTable>(&fErrors, /*builtin=*/false));
Stephen White88574972020-06-23 19:09:29 -04001924
1925 fRTHeightStructId = this->writeInterfaceBlock(intf, false);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001926 fRTHeightFieldIndex = 0;
Jim Van Verthf3ec9832020-10-21 16:09:57 -04001927 fRTHeightStorageClass = SpvStorageClassUniform;
Greg Daniela85e4bf2020-06-17 16:32:45 -04001928 }
1929 SkASSERT(fRTHeightFieldIndex != (SpvId)-1);
1930
1931 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1932 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1933 SpvId heightPtr = this->nextId();
1934 this->writeOpCode(SpvOpAccessChain, 5, out);
Jim Van Verthf3ec9832020-10-21 16:09:57 -04001935 this->writeWord(this->getPointerType(*fContext.fFloat_Type, fRTHeightStorageClass),
Greg Daniela85e4bf2020-06-17 16:32:45 -04001936 out);
1937 this->writeWord(heightPtr, out);
1938 this->writeWord(fRTHeightStructId, out);
1939 this->writeWord(fieldIndexId, out);
1940 SpvId heightRead = this->nextId();
1941 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1942 heightPtr, out);
1943
1944 flippedYId = this->nextId();
1945 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
1946 heightRead, rawYId, out);
1947 }
1948
1949 // The z component will always be zero so we just get an id to the 0 literal
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001950 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001951 SpvId zeroId = writeFloatLiteral(zero);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001952
Brian Osmane38bedd2020-12-21 11:51:54 -05001953 // Calculate the w component
Greg Daniela85e4bf2020-06-17 16:32:45 -04001954 SpvId rawWId = this->nextId();
1955 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawWId,
Ethan Nicholas20798e52018-12-04 12:30:50 -05001956 result, 3, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001957
1958 // Fill in the new fragcoord with the components from above
1959 SpvId adjusted = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001960 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001961 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001962 this->writeWord(adjusted, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001963 this->writeWord(xId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001964 if (fProgram.fSettings.fFlipY) {
1965 this->writeWord(flippedYId, out);
1966 } else {
1967 this->writeWord(rawYId, out);
1968 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001969 this->writeWord(zeroId, out);
Brian Osmane38bedd2020-12-21 11:51:54 -05001970 this->writeWord(rawWId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001971
1972 return adjusted;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001973 }
Ethan Nicholas78686922020-10-08 06:46:27 -04001974 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
Chris Daltonb91c4662018-08-01 10:46:22 -06001975 !fProgram.fSettings.fFlipY) {
1976 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1977 // the default convention of "counter-clockwise face is front".
1978 SpvId inverse = this->nextId();
1979 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1980 result, out);
1981 return inverse;
1982 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001983 return result;
1984}
1985
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001986SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05001987 if (expr.base()->type().isVector()) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001988 SpvId base = this->writeExpression(*expr.base(), out);
1989 SpvId index = this->writeExpression(*expr.index(), out);
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001990 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001991 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.type()), result, base,
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001992 index, out);
1993 return result;
1994 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001995 return getLValue(expr, out)->load(out);
1996}
1997
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001998SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001999 return getLValue(f, out)->load(out);
2000}
2001
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002002SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002003 SpvId base = this->writeExpression(*swizzle.base(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002004 SpvId result = this->nextId();
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002005 size_t count = swizzle.components().size();
ethannicholasb3058bd2016-07-01 08:22:01 -07002006 if (count == 1) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002007 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.type()), result, base,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002008 swizzle.components()[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002009 } else {
2010 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002011 this->writeWord(this->getType(swizzle.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002012 this->writeWord(result, out);
2013 this->writeWord(base, out);
Brian Osman25647672020-09-15 15:16:56 -04002014 this->writeWord(base, out);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002015 for (int component : swizzle.components()) {
Brian Osman25647672020-09-15 15:16:56 -04002016 this->writeWord(component, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002017 }
2018 }
2019 return result;
2020}
2021
Greg Daniel64773e62016-11-22 09:44:03 -05002022SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
2023 const Type& operandType, SpvId lhs,
2024 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002025 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002026 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002027 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002028 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002029 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002030 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002031 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002032 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
John Stiles123501f2020-12-09 10:08:13 -05002033 } else if (is_bool(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002034 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002035 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07002036 } else {
John Stiles123501f2020-12-09 10:08:13 -05002037 fErrors.error(operandType.fOffset,
2038 "unsupported operand for binary expression: " + operandType.description());
2039 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002040 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04002041 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002042 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
2043 fDecorationBuffer);
2044 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002045 return result;
2046}
2047
Ethan Nicholas48e24052018-03-14 13:51:39 -04002048SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
2049 OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05002050 if (operandType.isVector()) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002051 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04002052 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002053 return result;
2054 }
2055 return id;
2056}
2057
Ethan Nicholas68990be2017-07-13 09:36:52 -04002058SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
2059 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002060 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04002061 OutputStream& out) {
2062 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
John Stiles9aeed132020-11-24 17:36:06 -05002063 SkASSERT(operandType.isMatrix());
Ethan Nicholas0df21132018-07-10 09:37:51 -04002064 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2065 operandType.rows(),
2066 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04002067 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002068 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04002069 1));
2070 SpvId boolType = this->getType(*fContext.fBool_Type);
2071 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04002072 for (int i = 0; i < operandType.columns(); i++) {
2073 SpvId columnL = this->nextId();
2074 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2075 SpvId columnR = this->nextId();
2076 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002077 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002078 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
2079 SpvId merge = this->nextId();
2080 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002081 if (result != 0) {
2082 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002083 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002084 result = next;
2085 }
2086 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002087 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04002088 }
2089 }
2090 return result;
2091}
2092
Ethan Nicholas0df21132018-07-10 09:37:51 -04002093SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
2094 SpvId rhs, SpvOp_ floatOperator,
2095 SpvOp_ intOperator,
2096 OutputStream& out) {
2097 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
John Stiles9aeed132020-11-24 17:36:06 -05002098 SkASSERT(operandType.isMatrix());
Ethan Nicholas0df21132018-07-10 09:37:51 -04002099 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2100 operandType.rows(),
2101 1));
2102 SpvId columns[4];
2103 for (int i = 0; i < operandType.columns(); i++) {
2104 SpvId columnL = this->nextId();
2105 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2106 SpvId columnR = this->nextId();
2107 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2108 columns[i] = this->nextId();
2109 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2110 }
2111 SpvId result = this->nextId();
2112 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2113 this->writeWord(this->getType(operandType), out);
2114 this->writeWord(result, out);
2115 for (int i = 0; i < operandType.columns(); i++) {
2116 this->writeWord(columns[i], out);
2117 }
2118 return result;
2119}
2120
Ethan Nicholas49465b42019-04-17 12:22:21 -04002121std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2122 if (type.isInteger()) {
2123 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002124 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002125 else if (type.isFloat()) {
2126 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002127 } else {
Ethan Nicholase2c49992020-10-05 11:49:11 -04002128 ABORT("math is unsupported on type '%s'", String(type.name()).c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002129 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002130}
2131
2132SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Token::Kind op,
2133 const Type& rightType, SpvId rhs,
2134 const Type& resultType, OutputStream& out) {
John Stilesd0614f22020-12-09 11:11:41 -05002135 // The comma operator ignores the type of the left-hand side entirely.
2136 if (op == Token::Kind::TK_COMMA) {
2137 return rhs;
2138 }
Ethan Nicholas48e24052018-03-14 13:51:39 -04002139 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002140 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002141 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2142 // handling in SPIR-V
Ethan Nicholas49465b42019-04-17 12:22:21 -04002143 if (this->getActualType(leftType) != this->getActualType(rightType)) {
John Stiles9aeed132020-11-24 17:36:06 -05002144 if (leftType.isVector() && rightType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002145 if (op == Token::Kind::TK_SLASH) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002146 SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
2147 SpvId inverse = this->nextId();
2148 this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
2149 rhs = inverse;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002150 op = Token::Kind::TK_STAR;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002151 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002152 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002153 SpvId result = this->nextId();
2154 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2155 result, lhs, rhs, out);
2156 return result;
2157 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002158 // promote number to vector
2159 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002160 const Type& vecType = leftType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002161 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2162 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002163 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002164 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002165 this->writeWord(rhs, out);
2166 }
2167 rhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002168 operandType = &leftType;
John Stiles9aeed132020-11-24 17:36:06 -05002169 } else if (rightType.isVector() && leftType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002170 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002171 SpvId result = this->nextId();
2172 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2173 result, rhs, lhs, out);
2174 return result;
2175 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002176 // promote number to vector
2177 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002178 const Type& vecType = rightType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002179 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2180 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002181 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002182 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002183 this->writeWord(lhs, out);
2184 }
2185 lhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002186 operandType = &rightType;
John Stiles9aeed132020-11-24 17:36:06 -05002187 } else if (leftType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002188 SpvOp_ spvop;
John Stiles9aeed132020-11-24 17:36:06 -05002189 if (rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002190 spvop = SpvOpMatrixTimesMatrix;
John Stiles9aeed132020-11-24 17:36:06 -05002191 } else if (rightType.isVector()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002192 spvop = SpvOpMatrixTimesVector;
ethannicholasb3058bd2016-07-01 08:22:01 -07002193 } else {
John Stiles9aeed132020-11-24 17:36:06 -05002194 SkASSERT(rightType.isScalar());
Ethan Nicholas49465b42019-04-17 12:22:21 -04002195 spvop = SpvOpMatrixTimesScalar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002196 }
2197 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002198 this->writeInstruction(spvop, this->getType(resultType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002199 return result;
John Stiles9aeed132020-11-24 17:36:06 -05002200 } else if (rightType.isMatrix()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002201 SpvId result = this->nextId();
John Stiles9aeed132020-11-24 17:36:06 -05002202 if (leftType.isVector()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002203 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(resultType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002204 lhs, rhs, out);
2205 } else {
John Stiles9aeed132020-11-24 17:36:06 -05002206 SkASSERT(leftType.isScalar());
Ethan Nicholas49465b42019-04-17 12:22:21 -04002207 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(resultType), result,
2208 rhs, lhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002209 }
2210 return result;
2211 } else {
John Stilesd8ca6b62020-11-23 14:28:36 -05002212 fErrors.error(leftType.fOffset, "unsupported mixed-type expression");
Ethan Nicholas49465b42019-04-17 12:22:21 -04002213 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002214 }
2215 } else {
John Stiles2d4f9592020-10-30 10:29:12 -04002216 operandType = &this->getActualType(leftType);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002217 SkASSERT(*operandType == this->getActualType(rightType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002218 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002219 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002220 case Token::Kind::TK_EQEQ: {
John Stiles9aeed132020-11-24 17:36:06 -05002221 if (operandType->isMatrix()) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002222 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002223 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002224 }
John Stiles4a7dc462020-11-25 11:08:08 -05002225 SkASSERT(resultType.isBoolean());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002226 const Type* tmpType;
John Stiles9aeed132020-11-24 17:36:06 -05002227 if (operandType->isVector()) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002228 tmpType = &fContext.fBool_Type->toCompound(fContext,
2229 operandType->columns(),
2230 operandType->rows());
2231 } else {
2232 tmpType = &resultType;
2233 }
2234 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002235 SpvOpFOrdEqual, SpvOpIEqual,
2236 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002237 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002238 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002239 case Token::Kind::TK_NEQ:
John Stiles9aeed132020-11-24 17:36:06 -05002240 if (operandType->isMatrix()) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002241 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002242 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002243 }
John Stiles4a7dc462020-11-25 11:08:08 -05002244 [[fallthrough]];
2245 case Token::Kind::TK_LOGICALXOR:
2246 SkASSERT(resultType.isBoolean());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002247 const Type* tmpType;
John Stiles9aeed132020-11-24 17:36:06 -05002248 if (operandType->isVector()) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002249 tmpType = &fContext.fBool_Type->toCompound(fContext,
2250 operandType->columns(),
2251 operandType->rows());
2252 } else {
2253 tmpType = &resultType;
2254 }
2255 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002256 SpvOpFOrdNotEqual, SpvOpINotEqual,
2257 SpvOpINotEqual, SpvOpLogicalNotEqual,
2258 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002259 *operandType, SpvOpAny, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002260 case Token::Kind::TK_GT:
John Stiles4a7dc462020-11-25 11:08:08 -05002261 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002262 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2263 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002264 SpvOpUGreaterThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002265 case Token::Kind::TK_LT:
John Stiles4a7dc462020-11-25 11:08:08 -05002266 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002267 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002268 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002269 case Token::Kind::TK_GTEQ:
John Stiles4a7dc462020-11-25 11:08:08 -05002270 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002271 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2272 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002273 SpvOpUGreaterThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002274 case Token::Kind::TK_LTEQ:
John Stiles4a7dc462020-11-25 11:08:08 -05002275 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002276 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2277 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002278 SpvOpULessThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002279 case Token::Kind::TK_PLUS:
John Stiles9aeed132020-11-24 17:36:06 -05002280 if (leftType.isMatrix() && rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002281 SkASSERT(leftType == rightType);
2282 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002283 SpvOpFAdd, SpvOpIAdd, out);
2284 }
Greg Daniel64773e62016-11-22 09:44:03 -05002285 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002286 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002287 case Token::Kind::TK_MINUS:
John Stiles9aeed132020-11-24 17:36:06 -05002288 if (leftType.isMatrix() && rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002289 SkASSERT(leftType == rightType);
2290 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002291 SpvOpFSub, SpvOpISub, out);
2292 }
Greg Daniel64773e62016-11-22 09:44:03 -05002293 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002294 SpvOpISub, SpvOpISub, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002295 case Token::Kind::TK_STAR:
John Stiles9aeed132020-11-24 17:36:06 -05002296 if (leftType.isMatrix() && rightType.isMatrix()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002297 // matrix multiply
2298 SpvId result = this->nextId();
2299 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2300 lhs, rhs, out);
2301 return result;
2302 }
Greg Daniel64773e62016-11-22 09:44:03 -05002303 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002304 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002305 case Token::Kind::TK_SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002306 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002307 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002308 case Token::Kind::TK_PERCENT:
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002309 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2310 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002311 case Token::Kind::TK_SHL:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002312 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2313 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2314 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002315 case Token::Kind::TK_SHR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002316 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2317 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2318 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002319 case Token::Kind::TK_BITWISEAND:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002320 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2321 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002322 case Token::Kind::TK_BITWISEOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002323 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2324 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002325 case Token::Kind::TK_BITWISEXOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002326 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2327 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
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);
Ethan Nicholas7fb39362020-12-16 15:25:19 -05002622 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002623 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002624 StringStream bodyBuffer;
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002625 this->writeBlock((Block&) *f.body(), bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002626 write_stringstream(fVariableBuffer, out);
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002627 if (f.declaration().name() == "main") {
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002628 write_stringstream(fGlobalInitializersBuffer, out);
2629 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002630 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002631 if (fCurrentBlock) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002632 if (f.declaration().returnType() == *fContext.fVoid_Type) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002633 this->writeInstruction(SpvOpReturn, out);
2634 } else {
2635 this->writeInstruction(SpvOpUnreachable, out);
2636 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002637 }
2638 this->writeInstruction(SpvOpFunctionEnd, out);
2639 return result;
2640}
2641
2642void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2643 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002644 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002645 fDecorationBuffer);
2646 }
2647 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002648 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002649 fDecorationBuffer);
2650 }
2651 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002652 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002653 fDecorationBuffer);
2654 }
2655 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002656 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002657 fDecorationBuffer);
2658 }
Greg Daniel64773e62016-11-22 09:44:03 -05002659 if (layout.fInputAttachmentIndex >= 0) {
2660 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2661 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002662 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002663 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002664 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002665 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002666 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002667 fDecorationBuffer);
2668 }
2669}
2670
2671void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2672 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002673 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002674 layout.fLocation, fDecorationBuffer);
2675 }
2676 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002677 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002678 layout.fBinding, fDecorationBuffer);
2679 }
2680 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002681 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002682 layout.fIndex, fDecorationBuffer);
2683 }
2684 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002685 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002686 layout.fSet, fDecorationBuffer);
2687 }
Greg Daniel64773e62016-11-22 09:44:03 -05002688 if (layout.fInputAttachmentIndex >= 0) {
2689 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2690 layout.fInputAttachmentIndex, fDecorationBuffer);
2691 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002692 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002693 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002694 layout.fBuiltin, fDecorationBuffer);
2695 }
2696}
2697
Ethan Nicholas81d15112018-07-13 12:48:50 -04002698static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2699 switch (m.fLayout.fPrimitive) {
2700 case Layout::kPoints_Primitive:
2701 *outSkInCount = 1;
2702 break;
2703 case Layout::kLines_Primitive:
2704 *outSkInCount = 2;
2705 break;
2706 case Layout::kLinesAdjacency_Primitive:
2707 *outSkInCount = 4;
2708 break;
2709 case Layout::kTriangles_Primitive:
2710 *outSkInCount = 3;
2711 break;
2712 case Layout::kTrianglesAdjacency_Primitive:
2713 *outSkInCount = 6;
2714 break;
2715 default:
2716 return;
2717 }
2718}
2719
Stephen White88574972020-06-23 19:09:29 -04002720SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf, bool appendRTHeight) {
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002721 bool isBuffer = ((intf.variable().modifiers().fFlags & Modifiers::kBuffer_Flag) != 0);
2722 bool pushConstant = ((intf.variable().modifiers().fLayout.fFlags &
2723 Layout::kPushConstant_Flag) != 0);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002724 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2725 MemoryLayout(MemoryLayout::k430_Standard) :
2726 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002727 SpvId result = this->nextId();
John Stilesad2d4942020-12-11 16:55:58 -05002728 std::unique_ptr<Type> rtHeightStructType;
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002729 const Type* type = &intf.variable().type();
John Stiles21f5f452020-11-30 09:57:59 -05002730 if (!MemoryLayout::LayoutIsSupported(*type)) {
John Stiles0023c0c2020-11-16 13:32:18 -05002731 fErrors.error(type->fOffset, "type '" + type->name() + "' is not permitted here");
2732 return this->nextId();
2733 }
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002734 Modifiers intfModifiers = intf.variable().modifiers();
2735 SpvStorageClass_ storageClass = get_storage_class(intfModifiers);
Stephen White88574972020-06-23 19:09:29 -04002736 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Greg Daniele6ab9982018-08-22 13:56:32 +00002737 SkASSERT(fRTHeightStructId == (SpvId) -1);
2738 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002739 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002740 fRTHeightStructId = result;
2741 fRTHeightFieldIndex = fields.size();
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002742 fRTHeightStorageClass = storageClass;
John Stilesad2d4942020-12-11 16:55:58 -05002743 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME),
2744 fContext.fFloat_Type.get());
2745 rtHeightStructType = Type::MakeStructType(type->fOffset, type->name(), std::move(fields));
2746 type = rtHeightStructType.get();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002747 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002748 SpvId typeId;
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002749 if (intfModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osman133724c2020-10-28 14:14:39 -04002750 for (const ProgramElement* e : fProgram.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04002751 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04002752 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholas81d15112018-07-13 12:48:50 -04002753 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002754 }
2755 }
John Stilesad2d4942020-12-11 16:55:58 -05002756 typeId = this->getType(
2757 *Type::MakeArrayType("sk_in", intf.variable().type().componentType(), fSkInCount),
2758 memoryLayout);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002759 } else {
2760 typeId = this->getType(*type, memoryLayout);
2761 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002762 if (intfModifiers.fFlags & Modifiers::kBuffer_Flag) {
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002763 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002764 } else if (intfModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002765 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002766 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002767 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002768 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002769 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002770 Layout layout = intfModifiers.fLayout;
2771 if (intfModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002772 layout.fSet = 0;
2773 }
2774 this->writeLayout(layout, result);
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002775 fVariableMap[&intf.variable()] = result;
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(
John Stilesad2d4942020-12-11 16:55:58 -05002850 *Type::MakeArrayType("sk_in", type.componentType(), fSkInCount),
Brian Osmanc0213602020-10-06 14:43:32 -04002851 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::kDo:
John Stiles26f98502020-08-18 09:30:51 -04002919 this->writeDoStatement(s.as<DoStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002920 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002921 case Statement::Kind::kSwitch:
John Stiles26f98502020-08-18 09:30:51 -04002922 this->writeSwitchStatement(s.as<SwitchStatement>(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002923 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002924 case Statement::Kind::kBreak:
ethannicholasb3058bd2016-07-01 08:22:01 -07002925 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2926 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002927 case Statement::Kind::kContinue:
ethannicholasb3058bd2016-07-01 08:22:01 -07002928 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2929 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002930 case Statement::Kind::kDiscard:
ethannicholasb3058bd2016-07-01 08:22:01 -07002931 this->writeInstruction(SpvOpKill, out);
2932 break;
2933 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002934#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002935 ABORT("unsupported statement: %s", s.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002936#endif
2937 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002938 }
2939}
2940
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002941void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04002942 for (const std::unique_ptr<Statement>& stmt : b.children()) {
2943 this->writeStatement(*stmt, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002944 }
2945}
2946
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002947void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002948 SpvId test = this->writeExpression(*stmt.test(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002949 SpvId ifTrue = this->nextId();
2950 SpvId ifFalse = this->nextId();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002951 if (stmt.ifFalse()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002952 SpvId end = this->nextId();
2953 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2954 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2955 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002956 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002957 if (fCurrentBlock) {
2958 this->writeInstruction(SpvOpBranch, end, out);
2959 }
2960 this->writeLabel(ifFalse, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002961 this->writeStatement(*stmt.ifFalse(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002962 if (fCurrentBlock) {
2963 this->writeInstruction(SpvOpBranch, end, out);
2964 }
2965 this->writeLabel(end, out);
2966 } else {
2967 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2968 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2969 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002970 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002971 if (fCurrentBlock) {
2972 this->writeInstruction(SpvOpBranch, ifFalse, out);
2973 }
2974 this->writeLabel(ifFalse, out);
2975 }
2976}
2977
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002978void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04002979 if (f.initializer()) {
2980 this->writeStatement(*f.initializer(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002981 }
2982 SpvId header = this->nextId();
2983 SpvId start = this->nextId();
2984 SpvId body = this->nextId();
2985 SpvId next = this->nextId();
2986 fContinueTarget.push(next);
2987 SpvId end = this->nextId();
2988 fBreakTarget.push(end);
2989 this->writeInstruction(SpvOpBranch, header, out);
2990 this->writeLabel(header, out);
2991 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002992 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002993 this->writeLabel(start, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04002994 if (f.test()) {
2995 SpvId test = this->writeExpression(*f.test(), out);
ethannicholas22f939e2016-10-13 13:25:34 -07002996 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
Ethan Nicholas7fb39362020-12-16 15:25:19 -05002997 } else {
2998 this->writeInstruction(SpvOpBranch, body, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002999 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003000 this->writeLabel(body, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003001 this->writeStatement(*f.statement(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003002 if (fCurrentBlock) {
3003 this->writeInstruction(SpvOpBranch, next, out);
3004 }
3005 this->writeLabel(next, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003006 if (f.next()) {
3007 this->writeExpression(*f.next(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003008 }
3009 this->writeInstruction(SpvOpBranch, header, out);
3010 this->writeLabel(end, out);
3011 fBreakTarget.pop();
3012 fContinueTarget.pop();
3013}
3014
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003015void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003016 SpvId header = this->nextId();
3017 SpvId start = this->nextId();
3018 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003019 SpvId continueTarget = this->nextId();
3020 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003021 SpvId end = this->nextId();
3022 fBreakTarget.push(end);
3023 this->writeInstruction(SpvOpBranch, header, out);
3024 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003025 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003026 this->writeInstruction(SpvOpBranch, start, out);
3027 this->writeLabel(start, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003028 this->writeStatement(*d.statement(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003029 if (fCurrentBlock) {
3030 this->writeInstruction(SpvOpBranch, next, out);
3031 }
3032 this->writeLabel(next, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003033 SpvId test = this->writeExpression(*d.test(), out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003034 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
3035 this->writeLabel(continueTarget, out);
3036 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003037 this->writeLabel(end, out);
3038 fBreakTarget.pop();
3039 fContinueTarget.pop();
3040}
3041
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003042void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04003043 SpvId value = this->writeExpression(*s.value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003044 std::vector<SpvId> labels;
3045 SpvId end = this->nextId();
3046 SpvId defaultLabel = end;
3047 fBreakTarget.push(end);
3048 int size = 3;
John Stiles2d4f9592020-10-30 10:29:12 -04003049 auto& cases = s.cases();
3050 for (const std::unique_ptr<SwitchCase>& c : cases) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003051 SpvId label = this->nextId();
3052 labels.push_back(label);
John Stiles2d4f9592020-10-30 10:29:12 -04003053 if (c->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003054 size += 2;
3055 } else {
3056 defaultLabel = label;
3057 }
3058 }
3059 labels.push_back(end);
3060 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3061 this->writeOpCode(SpvOpSwitch, size, out);
3062 this->writeWord(value, out);
3063 this->writeWord(defaultLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04003064 for (size_t i = 0; i < cases.size(); ++i) {
3065 if (!cases[i]->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003066 continue;
3067 }
John Stiles2d4f9592020-10-30 10:29:12 -04003068 this->writeWord(cases[i]->value()->as<IntLiteral>().value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003069 this->writeWord(labels[i], out);
3070 }
John Stiles2d4f9592020-10-30 10:29:12 -04003071 for (size_t i = 0; i < cases.size(); ++i) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003072 this->writeLabel(labels[i], out);
John Stiles2d4f9592020-10-30 10:29:12 -04003073 for (const auto& stmt : cases[i]->statements()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003074 this->writeStatement(*stmt, out);
3075 }
3076 if (fCurrentBlock) {
3077 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3078 }
3079 }
3080 this->writeLabel(end, out);
3081 fBreakTarget.pop();
3082}
3083
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003084void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003085 if (r.expression()) {
3086 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.expression(), out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003087 out);
3088 } else {
3089 this->writeInstruction(SpvOpReturn, out);
3090 }
3091}
3092
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003093void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003094 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003095 int invocations = 1;
Brian Osman133724c2020-10-28 14:14:39 -04003096 for (const ProgramElement* e : fProgram.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003097 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04003098 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003099 if (m.fFlags & Modifiers::kIn_Flag) {
3100 if (m.fLayout.fInvocations != -1) {
3101 invocations = m.fLayout.fInvocations;
3102 }
3103 SpvId input;
3104 switch (m.fLayout.fPrimitive) {
3105 case Layout::kPoints_Primitive:
3106 input = SpvExecutionModeInputPoints;
3107 break;
3108 case Layout::kLines_Primitive:
3109 input = SpvExecutionModeInputLines;
3110 break;
3111 case Layout::kLinesAdjacency_Primitive:
3112 input = SpvExecutionModeInputLinesAdjacency;
3113 break;
3114 case Layout::kTriangles_Primitive:
3115 input = SpvExecutionModeTriangles;
3116 break;
3117 case Layout::kTrianglesAdjacency_Primitive:
3118 input = SpvExecutionModeInputTrianglesAdjacency;
3119 break;
3120 default:
3121 input = 0;
3122 break;
3123 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003124 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003125 if (input) {
3126 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3127 }
3128 } else if (m.fFlags & Modifiers::kOut_Flag) {
3129 SpvId output;
3130 switch (m.fLayout.fPrimitive) {
3131 case Layout::kPoints_Primitive:
3132 output = SpvExecutionModeOutputPoints;
3133 break;
3134 case Layout::kLineStrip_Primitive:
3135 output = SpvExecutionModeOutputLineStrip;
3136 break;
3137 case Layout::kTriangleStrip_Primitive:
3138 output = SpvExecutionModeOutputTriangleStrip;
3139 break;
3140 default:
3141 output = 0;
3142 break;
3143 }
3144 if (output) {
3145 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3146 }
3147 if (m.fLayout.fMaxVertices != -1) {
3148 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3149 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3150 out);
3151 }
3152 }
3153 }
3154 }
3155 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3156 invocations, out);
3157}
3158
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003159void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003160 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003161 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003162 std::set<SpvId> interfaceVars;
Brian Osman1f8f5752020-10-28 14:46:21 -04003163 // assign IDs to functions
Brian Osman133724c2020-10-28 14:14:39 -04003164 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003165 switch (e->kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04003166 case ProgramElement::Kind::kFunction: {
Brian Osman1179fcf2020-10-08 16:04:40 -04003167 const FunctionDefinition& f = e->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04003168 fFunctionMap[&f.declaration()] = this->nextId();
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003169 break;
3170 }
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003171 default:
3172 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003173 }
3174 }
Brian Osman133724c2020-10-28 14:14:39 -04003175 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003176 if (e->is<InterfaceBlock>()) {
Brian Osman1f8f5752020-10-28 14:46:21 -04003177 const InterfaceBlock& intf = e->as<InterfaceBlock>();
ethannicholasb3058bd2016-07-01 08:22:01 -07003178 SpvId id = this->writeInterfaceBlock(intf);
Brian Osman1f8f5752020-10-28 14:46:21 -04003179
3180 const Modifiers& modifiers = intf.variable().modifiers();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003181 if (((modifiers.fFlags & Modifiers::kIn_Flag) ||
3182 (modifiers.fFlags & Modifiers::kOut_Flag)) &&
3183 modifiers.fLayout.fBuiltin == -1 &&
Brian Osman010ce6a2020-10-19 16:34:10 -04003184 !is_dead(intf.variable(), fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003185 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003186 }
3187 }
3188 }
Brian Osman133724c2020-10-28 14:14:39 -04003189 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003190 if (e->is<GlobalVarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04003191 this->writeGlobalVar(program.fKind,
3192 e->as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>(),
3193 body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003194 }
3195 }
Brian Osman133724c2020-10-28 14:14:39 -04003196 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003197 if (e->is<FunctionDefinition>()) {
3198 this->writeFunction(e->as<FunctionDefinition>(), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003199 }
3200 }
ethannicholasd598f792016-07-25 10:08:54 -07003201 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003202 for (auto entry : fFunctionMap) {
Ethan Nicholase2c49992020-10-05 11:49:11 -04003203 if (entry.first->name() == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003204 main = entry.first;
3205 }
3206 }
Ethan Nicholas1a668d22019-04-18 10:37:40 -04003207 if (!main) {
3208 fErrors.error(0, "program does not contain a main() function");
3209 return;
3210 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003211 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003212 const Variable* var = entry.first;
Ethan Nicholas453f67f2020-10-09 10:43:45 -04003213 if (var->storage() == Variable::Storage::kGlobal &&
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003214 ((var->modifiers().fFlags & Modifiers::kIn_Flag) ||
Brian Osman010ce6a2020-10-19 16:34:10 -04003215 (var->modifiers().fFlags & Modifiers::kOut_Flag)) &&
3216 !is_dead(*var, fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003217 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003218 }
3219 }
3220 this->writeCapabilities(out);
3221 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3222 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003223 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->name().fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003224 (int32_t) interfaceVars.size(), out);
3225 switch (program.fKind) {
3226 case Program::kVertex_Kind:
3227 this->writeWord(SpvExecutionModelVertex, out);
3228 break;
3229 case Program::kFragment_Kind:
3230 this->writeWord(SpvExecutionModelFragment, out);
3231 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003232 case Program::kGeometry_Kind:
3233 this->writeWord(SpvExecutionModelGeometry, out);
3234 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003235 default:
3236 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003237 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003238 SpvId entryPoint = fFunctionMap[main];
3239 this->writeWord(entryPoint, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003240 this->writeString(main->name().fChars, main->name().fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003241 for (int var : interfaceVars) {
3242 this->writeWord(var, out);
3243 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003244 if (program.fKind == Program::kGeometry_Kind) {
3245 this->writeGeometryShaderExecutionMode(entryPoint, out);
3246 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003247 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003248 this->writeInstruction(SpvOpExecutionMode,
3249 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003250 SpvExecutionModeOriginUpperLeft,
3251 out);
3252 }
Brian Osman133724c2020-10-28 14:14:39 -04003253 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003254 if (e->is<Extension>()) {
3255 this->writeInstruction(SpvOpSourceExtension, e->as<Extension>().name().c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003256 }
3257 }
Greg Daniel64773e62016-11-22 09:44:03 -05003258
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003259 write_stringstream(fExtraGlobalsBuffer, out);
3260 write_stringstream(fNameBuffer, out);
3261 write_stringstream(fDecorationBuffer, out);
3262 write_stringstream(fConstantBuffer, out);
3263 write_stringstream(fExternalFunctionsBuffer, out);
3264 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003265}
3266
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003267bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003268 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003269 this->writeWord(SpvMagicNumber, *fOut);
3270 this->writeWord(SpvVersion, *fOut);
3271 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003272 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003273 this->writeInstructions(fProgram, buffer);
3274 this->writeWord(fIdCount, *fOut);
3275 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003276 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003277 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003278}
3279
John Stilesa6841be2020-08-06 14:11:56 -04003280} // namespace SkSL