blob: 186654604fde69b89c3c4afa06945c689845c211 [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Ethan Nicholasbcf35f82017-03-30 18:42:48 +00007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Ethan Nicholas9bd301d2017-03-31 16:04:34 +00009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "src/sksl/GLSL.std.450.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070011
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "src/sksl/SkSLCompiler.h"
13#include "src/sksl/ir/SkSLExpressionStatement.h"
14#include "src/sksl/ir/SkSLExtension.h"
15#include "src/sksl/ir/SkSLIndexExpression.h"
16#include "src/sksl/ir/SkSLVariableReference.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070017
Ethan Nicholas0be34802019-08-15 12:36:58 -040018#ifdef SK_VULKAN
19#include "src/gpu/vk/GrVkCaps.h"
20#endif
21
ethannicholasb3058bd2016-07-01 08:22:01 -070022namespace SkSL {
23
ethannicholasb3058bd2016-07-01 08:22:01 -070024static const int32_t SKSL_MAGIC = 0x0; // FIXME: we should probably register a magic number
25
26void SPIRVCodeGenerator::setupIntrinsics() {
27#define ALL_GLSL(x) std::make_tuple(kGLSL_STD_450_IntrinsicKind, GLSLstd450 ## x, GLSLstd450 ## x, \
28 GLSLstd450 ## x, GLSLstd450 ## x)
29#define BY_TYPE_GLSL(ifFloat, ifInt, ifUInt) std::make_tuple(kGLSL_STD_450_IntrinsicKind, \
30 GLSLstd450 ## ifFloat, \
31 GLSLstd450 ## ifInt, \
32 GLSLstd450 ## ifUInt, \
33 SpvOpUndef)
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040034#define ALL_SPIRV(x) std::make_tuple(kSPIRV_IntrinsicKind, SpvOp ## x, SpvOp ## x, SpvOp ## x, \
35 SpvOp ## x)
ethannicholasb3058bd2016-07-01 08:22:01 -070036#define SPECIAL(x) std::make_tuple(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic, \
37 k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
38 k ## x ## _SpecialIntrinsic)
Ethan Nicholas0df1b042017-03-31 13:56:23 -040039 fIntrinsicMap[String("round")] = ALL_GLSL(Round);
40 fIntrinsicMap[String("roundEven")] = ALL_GLSL(RoundEven);
41 fIntrinsicMap[String("trunc")] = ALL_GLSL(Trunc);
42 fIntrinsicMap[String("abs")] = BY_TYPE_GLSL(FAbs, SAbs, SAbs);
43 fIntrinsicMap[String("sign")] = BY_TYPE_GLSL(FSign, SSign, SSign);
44 fIntrinsicMap[String("floor")] = ALL_GLSL(Floor);
45 fIntrinsicMap[String("ceil")] = ALL_GLSL(Ceil);
46 fIntrinsicMap[String("fract")] = ALL_GLSL(Fract);
47 fIntrinsicMap[String("radians")] = ALL_GLSL(Radians);
48 fIntrinsicMap[String("degrees")] = ALL_GLSL(Degrees);
49 fIntrinsicMap[String("sin")] = ALL_GLSL(Sin);
50 fIntrinsicMap[String("cos")] = ALL_GLSL(Cos);
51 fIntrinsicMap[String("tan")] = ALL_GLSL(Tan);
52 fIntrinsicMap[String("asin")] = ALL_GLSL(Asin);
53 fIntrinsicMap[String("acos")] = ALL_GLSL(Acos);
54 fIntrinsicMap[String("atan")] = SPECIAL(Atan);
55 fIntrinsicMap[String("sinh")] = ALL_GLSL(Sinh);
56 fIntrinsicMap[String("cosh")] = ALL_GLSL(Cosh);
57 fIntrinsicMap[String("tanh")] = ALL_GLSL(Tanh);
58 fIntrinsicMap[String("asinh")] = ALL_GLSL(Asinh);
59 fIntrinsicMap[String("acosh")] = ALL_GLSL(Acosh);
60 fIntrinsicMap[String("atanh")] = ALL_GLSL(Atanh);
61 fIntrinsicMap[String("pow")] = ALL_GLSL(Pow);
62 fIntrinsicMap[String("exp")] = ALL_GLSL(Exp);
63 fIntrinsicMap[String("log")] = ALL_GLSL(Log);
64 fIntrinsicMap[String("exp2")] = ALL_GLSL(Exp2);
65 fIntrinsicMap[String("log2")] = ALL_GLSL(Log2);
66 fIntrinsicMap[String("sqrt")] = ALL_GLSL(Sqrt);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040067 fIntrinsicMap[String("inverse")] = ALL_GLSL(MatrixInverse);
68 fIntrinsicMap[String("transpose")] = ALL_SPIRV(Transpose);
John Stiles3679cd12020-12-09 16:22:12 -050069 fIntrinsicMap[String("isinf")] = ALL_SPIRV(IsInf);
70 fIntrinsicMap[String("isnan")] = ALL_SPIRV(IsNan);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040071 fIntrinsicMap[String("inversesqrt")] = ALL_GLSL(InverseSqrt);
72 fIntrinsicMap[String("determinant")] = ALL_GLSL(Determinant);
73 fIntrinsicMap[String("matrixInverse")] = ALL_GLSL(MatrixInverse);
Ethan Nicholas70a44b22017-11-30 09:09:16 -050074 fIntrinsicMap[String("mod")] = SPECIAL(Mod);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050075 fIntrinsicMap[String("min")] = SPECIAL(Min);
76 fIntrinsicMap[String("max")] = SPECIAL(Max);
77 fIntrinsicMap[String("clamp")] = SPECIAL(Clamp);
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040078 fIntrinsicMap[String("saturate")] = SPECIAL(Saturate);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040079 fIntrinsicMap[String("dot")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
Ethan Nicholas0187ae62017-05-03 11:03:44 -040080 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050081 fIntrinsicMap[String("mix")] = SPECIAL(Mix);
Brian Osman6ba3be12020-11-13 16:32:52 -050082 fIntrinsicMap[String("step")] = SPECIAL(Step);
83 fIntrinsicMap[String("smoothstep")] = SPECIAL(SmoothStep);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040084 fIntrinsicMap[String("fma")] = ALL_GLSL(Fma);
85 fIntrinsicMap[String("frexp")] = ALL_GLSL(Frexp);
86 fIntrinsicMap[String("ldexp")] = ALL_GLSL(Ldexp);
ethannicholasb3058bd2016-07-01 08:22:01 -070087
Ethan Nicholas0df1b042017-03-31 13:56:23 -040088#define PACK(type) fIntrinsicMap[String("pack" #type)] = ALL_GLSL(Pack ## type); \
89 fIntrinsicMap[String("unpack" #type)] = ALL_GLSL(Unpack ## type)
ethannicholasb3058bd2016-07-01 08:22:01 -070090 PACK(Snorm4x8);
91 PACK(Unorm4x8);
92 PACK(Snorm2x16);
93 PACK(Unorm2x16);
94 PACK(Half2x16);
95 PACK(Double2x32);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040096 fIntrinsicMap[String("length")] = ALL_GLSL(Length);
97 fIntrinsicMap[String("distance")] = ALL_GLSL(Distance);
98 fIntrinsicMap[String("cross")] = ALL_GLSL(Cross);
99 fIntrinsicMap[String("normalize")] = ALL_GLSL(Normalize);
100 fIntrinsicMap[String("faceForward")] = ALL_GLSL(FaceForward);
101 fIntrinsicMap[String("reflect")] = ALL_GLSL(Reflect);
102 fIntrinsicMap[String("refract")] = ALL_GLSL(Refract);
103 fIntrinsicMap[String("findLSB")] = ALL_GLSL(FindILsb);
104 fIntrinsicMap[String("findMSB")] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
105 fIntrinsicMap[String("dFdx")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400106 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700107 fIntrinsicMap[String("dFdy")] = SPECIAL(DFdy);
Chris Dalton09212192018-11-13 15:07:24 -0500108 fIntrinsicMap[String("fwidth")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFwidth,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400109 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400110 fIntrinsicMap[String("makeSampler2D")] = SPECIAL(SampledImage);
111
Ethan Nicholas13863662019-07-29 13:05:15 -0400112 fIntrinsicMap[String("sample")] = SPECIAL(Texture);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400113 fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
Greg Daniel64773e62016-11-22 09:44:03 -0500114
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400115 fIntrinsicMap[String("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400116 SpvOpUndef, SpvOpUndef, SpvOpAny);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400117 fIntrinsicMap[String("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400118 SpvOpUndef, SpvOpUndef, SpvOpAll);
Brian Osman540c13a2020-11-24 16:55:34 -0500119 fIntrinsicMap[String("not")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
120 SpvOpUndef, SpvOpUndef,
121 SpvOpLogicalNot);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400122 fIntrinsicMap[String("equal")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400123 SpvOpFOrdEqual, SpvOpIEqual,
124 SpvOpIEqual, SpvOpLogicalEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400125 fIntrinsicMap[String("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400126 SpvOpFOrdNotEqual, SpvOpINotEqual,
127 SpvOpINotEqual,
128 SpvOpLogicalNotEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400129 fIntrinsicMap[String("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500130 SpvOpFOrdLessThan, SpvOpSLessThan,
131 SpvOpULessThan, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400132 fIntrinsicMap[String("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500133 SpvOpFOrdLessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400134 SpvOpSLessThanEqual,
135 SpvOpULessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400136 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400137 fIntrinsicMap[String("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500138 SpvOpFOrdGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400139 SpvOpSGreaterThan,
140 SpvOpUGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400141 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400142 fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500143 SpvOpFOrdGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400144 SpvOpSGreaterThanEqual,
145 SpvOpUGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400146 SpvOpUndef);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400147 fIntrinsicMap[String("EmitVertex")] = ALL_SPIRV(EmitVertex);
148 fIntrinsicMap[String("EndPrimitive")] = ALL_SPIRV(EndPrimitive);
ethannicholasb3058bd2016-07-01 08:22:01 -0700149// interpolateAt* not yet supported...
150}
151
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400152void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700153 out.write((const char*) &word, sizeof(word));
ethannicholasb3058bd2016-07-01 08:22:01 -0700154}
155
ethannicholasd598f792016-07-25 10:08:54 -0700156static bool is_float(const Context& context, const Type& type) {
Ethan Nicholas0df21132018-07-10 09:37:51 -0400157 if (type.columns() > 1) {
ethannicholasd598f792016-07-25 10:08:54 -0700158 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700159 }
John Stiles123501f2020-12-09 10:08:13 -0500160 return type.isFloat();
ethannicholasb3058bd2016-07-01 08:22:01 -0700161}
162
ethannicholasd598f792016-07-25 10:08:54 -0700163static bool is_signed(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500164 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700165 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700166 }
John Stiles123501f2020-12-09 10:08:13 -0500167 return type.isSigned();
ethannicholasb3058bd2016-07-01 08:22:01 -0700168}
169
ethannicholasd598f792016-07-25 10:08:54 -0700170static bool is_unsigned(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_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700173 }
John Stiles123501f2020-12-09 10:08:13 -0500174 return type.isUnsigned();
ethannicholasb3058bd2016-07-01 08:22:01 -0700175}
176
ethannicholasd598f792016-07-25 10:08:54 -0700177static bool is_bool(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500178 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700179 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700180 }
John Stiles123501f2020-12-09 10:08:13 -0500181 return type.isBoolean();
ethannicholasb3058bd2016-07-01 08:22:01 -0700182}
183
ethannicholasd598f792016-07-25 10:08:54 -0700184static bool is_out(const Variable& var) {
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400185 return (var.modifiers().fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700186}
187
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400188void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400189 SkASSERT(opCode != SpvOpLoad || &out != &fConstantBuffer);
190 SkASSERT(opCode != SpvOpUndef);
ethannicholasb3058bd2016-07-01 08:22:01 -0700191 switch (opCode) {
192 case SpvOpReturn: // fall through
193 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700194 case SpvOpKill: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700195 case SpvOpBranch: // fall through
196 case SpvOpBranchConditional:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400197 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700198 fCurrentBlock = 0;
199 break;
200 case SpvOpConstant: // fall through
201 case SpvOpConstantTrue: // fall through
202 case SpvOpConstantFalse: // fall through
203 case SpvOpConstantComposite: // fall through
204 case SpvOpTypeVoid: // fall through
205 case SpvOpTypeInt: // fall through
206 case SpvOpTypeFloat: // fall through
207 case SpvOpTypeBool: // fall through
208 case SpvOpTypeVector: // fall through
209 case SpvOpTypeMatrix: // fall through
210 case SpvOpTypeArray: // fall through
211 case SpvOpTypePointer: // fall through
212 case SpvOpTypeFunction: // fall through
213 case SpvOpTypeRuntimeArray: // fall through
214 case SpvOpTypeStruct: // fall through
215 case SpvOpTypeImage: // fall through
216 case SpvOpTypeSampledImage: // fall through
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400217 case SpvOpTypeSampler: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700218 case SpvOpVariable: // fall through
219 case SpvOpFunction: // fall through
220 case SpvOpFunctionParameter: // fall through
221 case SpvOpFunctionEnd: // fall through
222 case SpvOpExecutionMode: // fall through
223 case SpvOpMemoryModel: // fall through
224 case SpvOpCapability: // fall through
225 case SpvOpExtInstImport: // fall through
226 case SpvOpEntryPoint: // fall through
227 case SpvOpSource: // fall through
228 case SpvOpSourceExtension: // fall through
229 case SpvOpName: // fall through
230 case SpvOpMemberName: // fall through
231 case SpvOpDecorate: // fall through
232 case SpvOpMemberDecorate:
233 break;
234 default:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400235 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700236 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700237 this->writeWord((length << 16) | opCode, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700238}
239
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400240void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700241 fCurrentBlock = label;
242 this->writeInstruction(SpvOpLabel, label, out);
243}
244
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400245void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700246 this->writeOpCode(opCode, 1, out);
247}
248
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400249void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700250 this->writeOpCode(opCode, 2, out);
251 this->writeWord(word1, out);
252}
253
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700254void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputStream& out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400255 out.write(string, length);
ethannicholasb3058bd2016-07-01 08:22:01 -0700256 switch (length % 4) {
257 case 1:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500258 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400259 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700260 case 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500261 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400262 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700263 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500264 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700265 break;
266 default:
267 this->writeWord(0, out);
268 }
269}
270
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700271void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out) {
272 this->writeOpCode(opCode, 1 + (string.fLength + 4) / 4, out);
273 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700274}
275
276
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700277void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400278 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700279 this->writeOpCode(opCode, 2 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700280 this->writeWord(word1, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700281 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700282}
283
Greg Daniel64773e62016-11-22 09:44:03 -0500284void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700285 StringFragment string, OutputStream& out) {
286 this->writeOpCode(opCode, 3 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700287 this->writeWord(word1, out);
288 this->writeWord(word2, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700289 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700290}
291
Greg Daniel64773e62016-11-22 09:44:03 -0500292void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400293 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700294 this->writeOpCode(opCode, 3, out);
295 this->writeWord(word1, out);
296 this->writeWord(word2, out);
297}
298
Greg Daniel64773e62016-11-22 09:44:03 -0500299void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400300 int32_t word3, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700301 this->writeOpCode(opCode, 4, out);
302 this->writeWord(word1, out);
303 this->writeWord(word2, out);
304 this->writeWord(word3, out);
305}
306
Greg Daniel64773e62016-11-22 09:44:03 -0500307void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400308 int32_t word3, int32_t word4, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700309 this->writeOpCode(opCode, 5, out);
310 this->writeWord(word1, out);
311 this->writeWord(word2, out);
312 this->writeWord(word3, out);
313 this->writeWord(word4, out);
314}
315
Greg Daniel64773e62016-11-22 09:44:03 -0500316void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
317 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400318 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700319 this->writeOpCode(opCode, 6, out);
320 this->writeWord(word1, out);
321 this->writeWord(word2, out);
322 this->writeWord(word3, out);
323 this->writeWord(word4, out);
324 this->writeWord(word5, out);
325}
326
Greg Daniel64773e62016-11-22 09:44:03 -0500327void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700328 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400329 int32_t word6, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700330 this->writeOpCode(opCode, 7, out);
331 this->writeWord(word1, out);
332 this->writeWord(word2, out);
333 this->writeWord(word3, out);
334 this->writeWord(word4, out);
335 this->writeWord(word5, out);
336 this->writeWord(word6, out);
337}
338
Greg Daniel64773e62016-11-22 09:44:03 -0500339void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700340 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400341 int32_t word6, int32_t word7, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700342 this->writeOpCode(opCode, 8, out);
343 this->writeWord(word1, out);
344 this->writeWord(word2, out);
345 this->writeWord(word3, out);
346 this->writeWord(word4, out);
347 this->writeWord(word5, out);
348 this->writeWord(word6, out);
349 this->writeWord(word7, out);
350}
351
Greg Daniel64773e62016-11-22 09:44:03 -0500352void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700353 int32_t word3, int32_t word4, int32_t word5,
354 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400355 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700356 this->writeOpCode(opCode, 9, out);
357 this->writeWord(word1, out);
358 this->writeWord(word2, out);
359 this->writeWord(word3, out);
360 this->writeWord(word4, out);
361 this->writeWord(word5, out);
362 this->writeWord(word6, out);
363 this->writeWord(word7, out);
364 this->writeWord(word8, out);
365}
366
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400367void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700368 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
369 if (fCapabilities & bit) {
370 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
371 }
372 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400373 if (fProgram.fKind == Program::kGeometry_Kind) {
374 this->writeInstruction(SpvOpCapability, SpvCapabilityGeometry, out);
375 }
Ethan Nicholas81d15112018-07-13 12:48:50 -0400376 else {
377 this->writeInstruction(SpvOpCapability, SpvCapabilityShader, out);
378 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700379}
380
381SpvId SPIRVCodeGenerator::nextId() {
382 return fIdCount++;
383}
384
Ethan Nicholas19671772016-11-28 16:30:17 -0500385void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
386 SpvId resultId) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400387 this->writeInstruction(SpvOpName, resultId, String(type.name()).c_str(), fNameBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700388 // go ahead and write all of the field types, so we don't inadvertently write them while we're
389 // in the middle of writing the struct instruction
390 std::vector<SpvId> types;
391 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500392 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700393 }
394 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
395 this->writeWord(resultId, fConstantBuffer);
396 for (SpvId id : types) {
397 this->writeWord(id, fConstantBuffer);
398 }
399 size_t offset = 0;
400 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400401 const Type::Field& field = type.fields()[i];
John Stiles21f5f452020-11-30 09:57:59 -0500402 if (!MemoryLayout::LayoutIsSupported(*field.fType)) {
John Stiles0023c0c2020-11-16 13:32:18 -0500403 fErrors.error(type.fOffset, "type '" + field.fType->name() + "' is not permitted here");
404 return;
405 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400406 size_t size = memoryLayout.size(*field.fType);
407 size_t alignment = memoryLayout.alignment(*field.fType);
408 const Layout& fieldLayout = field.fModifiers.fLayout;
Ethan Nicholas19671772016-11-28 16:30:17 -0500409 if (fieldLayout.fOffset >= 0) {
Greg Danieldbd44c72017-01-24 15:12:12 -0500410 if (fieldLayout.fOffset < (int) offset) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700411 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400412 "offset of field '" + field.fName + "' must be at "
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500413 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -0500414 }
415 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700416 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400417 "offset of field '" + field.fName + "' must be a multiple"
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500418 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -0500419 }
420 offset = fieldLayout.fOffset;
421 } else {
422 size_t mod = offset % alignment;
423 if (mod) {
424 offset += alignment - mod;
425 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700426 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400427 this->writeInstruction(SpvOpMemberName, resultId, i, field.fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500428 this->writeLayout(fieldLayout, resultId, i);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400429 if (field.fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -0500430 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700431 (SpvId) offset, fDecorationBuffer);
432 }
John Stiles9aeed132020-11-24 17:36:06 -0500433 if (field.fType->isMatrix()) {
Greg Daniel64773e62016-11-22 09:44:03 -0500434 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -0700435 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500436 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400437 (SpvId) memoryLayout.stride(*field.fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800438 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700439 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400440 if (!field.fType->highPrecision()) {
441 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i,
442 SpvDecorationRelaxedPrecision, fDecorationBuffer);
443 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700444 offset += size;
John Stilesc0c51062020-12-03 17:16:29 -0500445 if ((field.fType->isArray() || field.fType->isStruct()) && offset % alignment != 0) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700446 offset += alignment - offset % alignment;
447 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700448 }
449}
450
Ethan Nicholase2c49992020-10-05 11:49:11 -0400451const Type& SPIRVCodeGenerator::getActualType(const Type& type) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500452 if (type.isFloat()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400453 return *fContext.fFloat_Type;
454 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500455 if (type.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400456 return *fContext.fInt_Type;
457 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500458 if (type.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400459 return *fContext.fUInt_Type;
460 }
John Stiles9aeed132020-11-24 17:36:06 -0500461 if (type.isMatrix() || type.isVector()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400462 if (type.componentType() == *fContext.fHalf_Type) {
463 return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
464 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400465 if (type.componentType() == *fContext.fShort_Type ||
466 type.componentType() == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400467 return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
468 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400469 if (type.componentType() == *fContext.fUShort_Type ||
470 type.componentType() == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400471 return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
472 }
473 }
474 return type;
475}
476
ethannicholasb3058bd2016-07-01 08:22:01 -0700477SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800478 return this->getType(type, fDefaultLayout);
479}
480
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400481SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400482 const Type& type = this->getActualType(rawType);
Jim Van Verthf3ec9832020-10-21 16:09:57 -0400483 String key = type.name();
John Stilesc0c51062020-12-03 17:16:29 -0500484 if (type.isStruct() || type.isArray()) {
Jim Van Verthf3ec9832020-10-21 16:09:57 -0400485 key += to_string((int)layout.fStd);
486 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800487 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700488 if (entry == fTypeMap.end()) {
489 SpvId result = this->nextId();
Ethan Nicholase6592142020-09-08 10:22:09 -0400490 switch (type.typeKind()) {
491 case Type::TypeKind::kScalar:
John Stiles4a7dc462020-11-25 11:08:08 -0500492 if (type.isBoolean()) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700493 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500494 } else if (type == *fContext.fInt_Type || type == *fContext.fShort_Type ||
495 type == *fContext.fIntLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700496 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500497 } else if (type == *fContext.fUInt_Type || type == *fContext.fUShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700498 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500499 } else if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type ||
500 type == *fContext.fFloatLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700501 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700502 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400503 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700504 }
505 break;
John Stilesfd41d872020-11-25 22:39:45 -0500506 case Type::TypeKind::kEnum:
507 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
508 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400509 case Type::TypeKind::kVector:
Greg Daniel64773e62016-11-22 09:44:03 -0500510 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800511 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700512 type.columns(), fConstantBuffer);
513 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400514 case Type::TypeKind::kMatrix:
Greg Daniel64773e62016-11-22 09:44:03 -0500515 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800516 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700517 type.columns(), fConstantBuffer);
518 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400519 case Type::TypeKind::kStruct:
ethannicholas8ac838d2016-11-22 08:39:36 -0800520 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700521 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400522 case Type::TypeKind::kArray: {
John Stiles21f5f452020-11-30 09:57:59 -0500523 if (!MemoryLayout::LayoutIsSupported(type)) {
524 fErrors.error(type.fOffset, "type '" + type.name() + "' is not permitted here");
525 return this->nextId();
526 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700527 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700528 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500529 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800530 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700531 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500532 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400533 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800534 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700535 } else {
John Stiles5570c512020-11-19 17:58:07 -0500536 // We shouldn't have any runtime-sized arrays right now
537 fErrors.error(type.fOffset, "runtime-sized arrays are not supported in SPIR-V");
Greg Daniel64773e62016-11-22 09:44:03 -0500538 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800539 this->getType(type.componentType(), layout),
540 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400541 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
542 (int32_t) layout.stride(type),
543 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700544 }
545 break;
546 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400547 case Type::TypeKind::kSampler: {
Greg Daniel64773e62016-11-22 09:44:03 -0500548 SpvId image = result;
549 if (SpvDimSubpassData != type.dimensions()) {
Stephen White792e2302019-08-09 13:33:51 -0400550 image = this->getType(type.textureType(), layout);
Greg Daniel64773e62016-11-22 09:44:03 -0500551 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400552 if (SpvDimBuffer == type.dimensions()) {
553 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
554 }
Greg Daniel64773e62016-11-22 09:44:03 -0500555 if (SpvDimSubpassData != type.dimensions()) {
556 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
557 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700558 break;
559 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400560 case Type::TypeKind::kSeparateSampler: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400561 this->writeInstruction(SpvOpTypeSampler, result, fConstantBuffer);
562 break;
563 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400564 case Type::TypeKind::kTexture: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400565 this->writeInstruction(SpvOpTypeImage, result,
566 this->getType(*fContext.fFloat_Type, layout),
John Stilesc0c51062020-12-03 17:16:29 -0500567 type.dimensions(), type.isDepth(), type.isArrayedTexture(),
Stephen White792e2302019-08-09 13:33:51 -0400568 type.isMultisampled(), type.isSampled() ? 1 : 2,
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400569 SpvImageFormatUnknown, fConstantBuffer);
570 fImageTypeMap[key] = result;
571 break;
572 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700573 default:
ethannicholasd598f792016-07-25 10:08:54 -0700574 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700575 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
576 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500577#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700578 ABORT("invalid type: %s", type.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500579#endif
ethannicholasb3058bd2016-07-01 08:22:01 -0700580 }
581 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800582 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700583 return result;
584 }
585 return entry->second;
586}
587
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400588SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400589 SkASSERT(type.typeKind() == Type::TypeKind::kSampler);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400590 this->getType(type);
591 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400592 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400593 return fImageTypeMap[key];
594}
595
ethannicholasd598f792016-07-25 10:08:54 -0700596SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400597 String key = to_string(this->getType(function.returnType())) + "(";
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400598 String separator;
Brian Osman5bf3e202020-10-13 10:34:18 -0400599 const std::vector<const Variable*>& parameters = function.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400600 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700601 key += separator;
602 separator = ", ";
Ethan Nicholased84b732020-10-08 11:45:44 -0400603 key += to_string(this->getType(parameters[i]->type()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700604 }
605 key += ")";
606 auto entry = fTypeMap.find(key);
607 if (entry == fTypeMap.end()) {
608 SpvId result = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -0400609 int32_t length = 3 + (int32_t) parameters.size();
610 SpvId returnType = this->getType(function.returnType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700611 std::vector<SpvId> parameterTypes;
Ethan Nicholased84b732020-10-08 11:45:44 -0400612 for (size_t i = 0; i < parameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500613 // glslang seems to treat all function arguments as pointers whether they need to be or
614 // not. I was initially puzzled by this until I ran bizarre failures with certain
615 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700616 // failure case:
617 //
618 // void sphere(float x) {
619 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500620 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700621 // void map() {
622 // sphere(1.0);
623 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500624 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700625 // void main() {
626 // for (int i = 0; i < 1; i++) {
627 // map();
628 // }
629 // }
630 //
Greg Daniel64773e62016-11-22 09:44:03 -0500631 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
632 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700633 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
634 // the spec makes this make sense.
635// if (is_out(function->fParameters[i])) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400636 parameterTypes.push_back(this->getPointerType(parameters[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -0700637 SpvStorageClassFunction));
638// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700639// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700640// }
641 }
642 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
643 this->writeWord(result, fConstantBuffer);
644 this->writeWord(returnType, fConstantBuffer);
645 for (SpvId id : parameterTypes) {
646 this->writeWord(id, fConstantBuffer);
647 }
648 fTypeMap[key] = result;
649 return result;
650 }
651 return entry->second;
652}
653
ethannicholas8ac838d2016-11-22 08:39:36 -0800654SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
655 return this->getPointerType(type, fDefaultLayout, storageClass);
656}
657
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400658SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700659 SpvStorageClass_ storageClass) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400660 const Type& type = this->getActualType(rawType);
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500661 String key = type.displayName() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700662 auto entry = fTypeMap.find(key);
663 if (entry == fTypeMap.end()) {
664 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500665 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700666 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700667 fTypeMap[key] = result;
668 return result;
669 }
670 return entry->second;
671}
672
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400673SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400674 switch (expr.kind()) {
675 case Expression::Kind::kBinary:
John Stiles81365af2020-08-18 09:24:00 -0400676 return this->writeBinaryExpression(expr.as<BinaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400677 case Expression::Kind::kBoolLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400678 return this->writeBoolLiteral(expr.as<BoolLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400679 case Expression::Kind::kConstructor:
John Stiles81365af2020-08-18 09:24:00 -0400680 return this->writeConstructor(expr.as<Constructor>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400681 case Expression::Kind::kIntLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400682 return this->writeIntLiteral(expr.as<IntLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400683 case Expression::Kind::kFieldAccess:
John Stiles81365af2020-08-18 09:24:00 -0400684 return this->writeFieldAccess(expr.as<FieldAccess>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400685 case Expression::Kind::kFloatLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400686 return this->writeFloatLiteral(expr.as<FloatLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400687 case Expression::Kind::kFunctionCall:
John Stiles81365af2020-08-18 09:24:00 -0400688 return this->writeFunctionCall(expr.as<FunctionCall>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400689 case Expression::Kind::kPrefix:
John Stiles81365af2020-08-18 09:24:00 -0400690 return this->writePrefixExpression(expr.as<PrefixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400691 case Expression::Kind::kPostfix:
John Stiles81365af2020-08-18 09:24:00 -0400692 return this->writePostfixExpression(expr.as<PostfixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400693 case Expression::Kind::kSwizzle:
John Stiles81365af2020-08-18 09:24:00 -0400694 return this->writeSwizzle(expr.as<Swizzle>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400695 case Expression::Kind::kVariableReference:
John Stiles81365af2020-08-18 09:24:00 -0400696 return this->writeVariableReference(expr.as<VariableReference>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400697 case Expression::Kind::kTernary:
John Stiles81365af2020-08-18 09:24:00 -0400698 return this->writeTernaryExpression(expr.as<TernaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400699 case Expression::Kind::kIndex:
John Stiles81365af2020-08-18 09:24:00 -0400700 return this->writeIndexExpression(expr.as<IndexExpression>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700701 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500702#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700703 ABORT("unsupported expression: %s", expr.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500704#endif
705 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700706 }
707 return -1;
708}
709
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400710SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400711 const FunctionDeclaration& function = c.function();
John Stiles8e3b6be2020-10-13 11:14:08 -0400712 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400713 auto intrinsic = fIntrinsicMap.find(function.name());
John Stiles93e661a2020-12-08 16:17:00 -0500714 if (intrinsic == fIntrinsicMap.end()) {
715 fErrors.error(c.fOffset, "unsupported intrinsic '" + function.description() + "'");
716 return -1;
717 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700718 int32_t intrinsicId;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400719 if (arguments.size() > 0) {
720 const Type& type = arguments[0]->type();
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400721 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
722 intrinsicId = std::get<1>(intrinsic->second);
723 } else if (is_signed(fContext, type)) {
724 intrinsicId = std::get<2>(intrinsic->second);
725 } else if (is_unsigned(fContext, type)) {
726 intrinsicId = std::get<3>(intrinsic->second);
727 } else if (is_bool(fContext, type)) {
728 intrinsicId = std::get<4>(intrinsic->second);
729 } else {
730 intrinsicId = std::get<1>(intrinsic->second);
731 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700732 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400733 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700734 }
735 switch (std::get<0>(intrinsic->second)) {
736 case kGLSL_STD_450_IntrinsicKind: {
737 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400738 std::vector<SpvId> argumentIds;
739 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400740 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400741 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400742 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400743 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400744 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700745 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400746 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400747 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700748 this->writeWord(result, out);
749 this->writeWord(fGLSLExtendedInstructions, out);
750 this->writeWord(intrinsicId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400751 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700752 this->writeWord(id, out);
753 }
754 return result;
755 }
756 case kSPIRV_IntrinsicKind: {
Brian Osman46787d52020-11-24 14:18:23 -0500757 // GLSL supports dot(float, float), but SPIR-V does not. Convert it to FMul
John Stiles9aeed132020-11-24 17:36:06 -0500758 if (intrinsicId == SpvOpDot && arguments[0]->type().isScalar()) {
Brian Osman46787d52020-11-24 14:18:23 -0500759 intrinsicId = SpvOpFMul;
760 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700761 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400762 std::vector<SpvId> argumentIds;
763 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400764 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400765 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400766 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400767 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400768 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700769 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400770 if (c.type() != *fContext.fVoid_Type) {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400771 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400772 this->writeWord(this->getType(c.type()), out);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400773 this->writeWord(result, out);
774 } else {
775 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
776 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400777 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700778 this->writeWord(id, out);
779 }
780 return result;
781 }
782 case kSpecial_IntrinsicKind:
783 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
784 default:
John Stiles93e661a2020-12-08 16:17:00 -0500785 fErrors.error(c.fOffset, "unsupported intrinsic '" + function.description() + "'");
786 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700787 }
788}
789
John Stiles8e3b6be2020-10-13 11:14:08 -0400790std::vector<SpvId> SPIRVCodeGenerator::vectorize(const ExpressionArray& args, OutputStream& out) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500791 int vectorSize = 0;
792 for (const auto& a : args) {
John Stiles9aeed132020-11-24 17:36:06 -0500793 if (a->type().isVector()) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500794 if (vectorSize) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400795 SkASSERT(a->type().columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500796 }
797 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400798 vectorSize = a->type().columns();
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500799 }
800 }
801 }
802 std::vector<SpvId> result;
John Stiles8e3b6be2020-10-13 11:14:08 -0400803 result.reserve(args.size());
Ethan Nicholas30d30222020-09-11 12:27:26 -0400804 for (const auto& arg : args) {
805 const Type& argType = arg->type();
806 SpvId raw = this->writeExpression(*arg, out);
John Stiles9aeed132020-11-24 17:36:06 -0500807 if (vectorSize && argType.isScalar()) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500808 SpvId vector = this->nextId();
809 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400810 this->writeWord(this->getType(argType.toCompound(fContext, vectorSize, 1)), out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500811 this->writeWord(vector, out);
812 for (int i = 0; i < vectorSize; i++) {
813 this->writeWord(raw, out);
814 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400815 this->writePrecisionModifier(argType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500816 result.push_back(vector);
817 } else {
818 result.push_back(raw);
819 }
820 }
821 return result;
822}
823
824void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
825 SpvId signedInst, SpvId unsignedInst,
826 const std::vector<SpvId>& args,
827 OutputStream& out) {
828 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
829 this->writeWord(this->getType(type), out);
830 this->writeWord(id, out);
831 this->writeWord(fGLSLExtendedInstructions, out);
832
833 if (is_float(fContext, type)) {
834 this->writeWord(floatInst, out);
835 } else if (is_signed(fContext, type)) {
836 this->writeWord(signedInst, out);
837 } else if (is_unsigned(fContext, type)) {
838 this->writeWord(unsignedInst, out);
839 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400840 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500841 }
842 for (SpvId a : args) {
843 this->writeWord(a, out);
844 }
845}
846
Greg Daniel64773e62016-11-22 09:44:03 -0500847SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400848 OutputStream& out) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400849 const ExpressionArray& arguments = c.arguments();
ethannicholasb3058bd2016-07-01 08:22:01 -0700850 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400851 const Type& callType = c.type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700852 switch (kind) {
853 case kAtan_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400854 std::vector<SpvId> argumentIds;
855 for (const std::unique_ptr<Expression>& arg : arguments) {
856 argumentIds.push_back(this->writeExpression(*arg, out));
ethannicholasb3058bd2016-07-01 08:22:01 -0700857 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400858 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400859 this->writeWord(this->getType(callType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700860 this->writeWord(result, out);
861 this->writeWord(fGLSLExtendedInstructions, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400862 this->writeWord(argumentIds.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
863 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700864 this->writeWord(id, out);
865 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400866 break;
867 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400868 case kSampledImage_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400869 SkASSERT(arguments.size() == 2);
870 SpvId img = this->writeExpression(*arguments[0], out);
871 SpvId sampler = this->writeExpression(*arguments[1], out);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400872 this->writeInstruction(SpvOpSampledImage,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400873 this->getType(callType),
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400874 result,
875 img,
876 sampler,
877 out);
878 break;
879 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400880 case kSubpassLoad_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400881 SpvId img = this->writeExpression(*arguments[0], out);
John Stiles8e3b6be2020-10-13 11:14:08 -0400882 ExpressionArray args;
John Stilesf4bda742020-10-14 16:57:41 -0400883 args.reserve_back(2);
John Stiles8e3b6be2020-10-13 11:14:08 -0400884 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
885 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
Ethan Nicholas30d30222020-09-11 12:27:26 -0400886 Constructor ctor(-1, fContext.fInt2_Type.get(), std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400887 SpvId coords = this->writeConstantVector(ctor);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400888 if (arguments.size() == 1) {
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400889 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400890 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400891 result,
892 img,
893 coords,
894 out);
895 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400896 SkASSERT(arguments.size() == 2);
897 SpvId sample = this->writeExpression(*arguments[1], out);
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 SpvImageOperandsSampleMask,
904 sample,
905 out);
906 }
907 break;
908 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700909 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500910 SpvOp_ op = SpvOpImageSampleImplicitLod;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400911 const Type& arg1Type = arguments[1]->type();
912 switch (arguments[0]->type().dimensions()) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500913 case SpvDim1D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400914 if (arg1Type == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500915 op = SpvOpImageSampleProjImplicitLod;
916 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400917 SkASSERT(arg1Type == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500918 }
919 break;
920 case SpvDim2D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400921 if (arg1Type == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500922 op = SpvOpImageSampleProjImplicitLod;
923 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400924 SkASSERT(arg1Type == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500925 }
926 break;
927 case SpvDim3D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400928 if (arg1Type == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500929 op = SpvOpImageSampleProjImplicitLod;
930 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400931 SkASSERT(arg1Type == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500932 }
933 break;
934 case SpvDimCube: // fall through
935 case SpvDimRect: // fall through
936 case SpvDimBuffer: // fall through
937 case SpvDimSubpassData:
938 break;
939 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400940 SpvId type = this->getType(callType);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400941 SpvId sampler = this->writeExpression(*arguments[0], out);
942 SpvId uv = this->writeExpression(*arguments[1], out);
943 if (arguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500944 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700945 SpvImageOperandsBiasMask,
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400946 this->writeExpression(*arguments[2], out),
ethannicholasb3058bd2016-07-01 08:22:01 -0700947 out);
948 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400949 SkASSERT(arguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500950 if (fProgram.fSettings.fSharpenTextures) {
951 FloatLiteral lodBias(fContext, -1, -0.5);
952 this->writeInstruction(op, type, result, sampler, uv,
953 SpvImageOperandsBiasMask,
954 this->writeFloatLiteral(lodBias),
955 out);
956 } else {
957 this->writeInstruction(op, type, result, sampler, uv,
958 out);
959 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700960 }
961 break;
962 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500963 case kMod_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400964 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400965 SkASSERT(args.size() == 2);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400966 const Type& operandType = arguments[0]->type();
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500967 SpvOp_ op;
968 if (is_float(fContext, operandType)) {
969 op = SpvOpFMod;
970 } else if (is_signed(fContext, operandType)) {
971 op = SpvOpSMod;
972 } else if (is_unsigned(fContext, operandType)) {
973 op = SpvOpUMod;
974 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400975 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500976 return 0;
977 }
978 this->writeOpCode(op, 5, out);
979 this->writeWord(this->getType(operandType), out);
980 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500981 this->writeWord(args[0], out);
982 this->writeWord(args[1], out);
983 break;
984 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700985 case kDFdy_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400986 SpvId fn = this->writeExpression(*arguments[0], out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700987 this->writeOpCode(SpvOpDPdy, 4, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400988 this->writeWord(this->getType(callType), out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700989 this->writeWord(result, out);
990 this->writeWord(fn, out);
991 if (fProgram.fSettings.fFlipY) {
992 // Flipping Y also negates the Y derivatives.
993 SpvId flipped = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400994 this->writeInstruction(SpvOpFNegate, this->getType(callType), flipped, result,
995 out);
996 this->writePrecisionModifier(callType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700997 return flipped;
998 }
999 break;
1000 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001001 case kClamp_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001002 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001003 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001004 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001005 GLSLstd450UClamp, args, out);
1006 break;
1007 }
1008 case kMax_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001009 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001010 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001011 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMax, GLSLstd450SMax,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001012 GLSLstd450UMax, args, out);
1013 break;
1014 }
1015 case kMin_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001016 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001017 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001018 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMin, GLSLstd450SMin,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001019 GLSLstd450UMin, args, out);
1020 break;
1021 }
1022 case kMix_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001023 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001024 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001025 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMix, SpvOpUndef,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001026 SpvOpUndef, args, out);
1027 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -05001028 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001029 case kSaturate_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001030 SkASSERT(arguments.size() == 1);
John Stiles8e3b6be2020-10-13 11:14:08 -04001031 ExpressionArray finalArgs;
John Stilesf4bda742020-10-14 16:57:41 -04001032 finalArgs.reserve_back(3);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001033 finalArgs.push_back(arguments[0]->clone());
John Stiles8e3b6be2020-10-13 11:14:08 -04001034 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1035 /*value=*/0));
1036 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1037 /*value=*/1));
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001038 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001039 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001040 GLSLstd450UClamp, spvArgs, out);
1041 break;
1042 }
Brian Osman6ba3be12020-11-13 16:32:52 -05001043 case kSmoothStep_SpecialIntrinsic: {
1044 std::vector<SpvId> args = this->vectorize(arguments, out);
1045 SkASSERT(args.size() == 3);
1046 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450SmoothStep, SpvOpUndef,
1047 SpvOpUndef, args, out);
1048 break;
1049 }
1050 case kStep_SpecialIntrinsic: {
1051 std::vector<SpvId> args = this->vectorize(arguments, out);
1052 SkASSERT(args.size() == 2);
1053 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450Step, SpvOpUndef,
1054 SpvOpUndef, args, out);
1055 break;
1056 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001057 }
1058 return result;
1059}
1060
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001061SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001062 const FunctionDeclaration& function = c.function();
John Stiles8e3b6be2020-10-13 11:14:08 -04001063 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001064 const auto& entry = fFunctionMap.find(&function);
ethannicholasb3058bd2016-07-01 08:22:01 -07001065 if (entry == fFunctionMap.end()) {
1066 return this->writeIntrinsicCall(c, out);
1067 }
1068 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001069 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001070 std::vector<SpvId> argumentIds;
1071 for (size_t i = 0; i < arguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001072 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001073 // passed directly
1074 SpvId tmpVar;
1075 // if we need a temporary var to store this argument, this is the value to store in the var
1076 SpvId tmpValueId;
Ethan Nicholased84b732020-10-08 11:45:44 -04001077 if (is_out(*function.parameters()[i])) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001078 std::unique_ptr<LValue> lv = this->getLValue(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001079 SpvId ptr = lv->getPointer();
1080 if (ptr) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001081 argumentIds.push_back(ptr);
ethannicholasb3058bd2016-07-01 08:22:01 -07001082 continue;
1083 } else {
1084 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1085 // copy it into a temp, call the function, read the value out of the temp, and then
1086 // update the lvalue.
1087 tmpValueId = lv->load(out);
1088 tmpVar = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001089 lvalues.push_back(std::make_tuple(tmpVar, &arguments[i]->type(), std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001090 }
1091 } else {
1092 // see getFunctionType for an explanation of why we're always using pointer parameters
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001093 tmpValueId = this->writeExpression(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001094 tmpVar = this->nextId();
1095 }
Greg Daniel64773e62016-11-22 09:44:03 -05001096 this->writeInstruction(SpvOpVariable,
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001097 this->getPointerType(arguments[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001098 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001099 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001100 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001101 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001102 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001103 argumentIds.push_back(tmpVar);
ethannicholasb3058bd2016-07-01 08:22:01 -07001104 }
1105 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001106 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001107 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001108 this->writeWord(result, out);
1109 this->writeWord(entry->second, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001110 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001111 this->writeWord(id, out);
1112 }
1113 // now that the call is complete, we may need to update some lvalues with the new values of out
1114 // arguments
1115 for (const auto& tuple : lvalues) {
1116 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001117 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1118 out);
1119 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001120 std::get<2>(tuple)->store(load, out);
1121 }
1122 return result;
1123}
1124
ethannicholasf789b382016-08-03 12:43:36 -07001125SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001126 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001127 SkASSERT(type.isVector() && c.isCompileTimeConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001128 SpvId result = this->nextId();
1129 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001130 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1131 arguments.push_back(this->writeExpression(*arg, fConstantBuffer));
ethannicholasb3058bd2016-07-01 08:22:01 -07001132 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001133 SpvId typeId = this->getType(type);
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001134 if (c.arguments().size() == 1) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001135 // with a single argument, a vector will have all of its entries equal to the argument
Ethan Nicholas30d30222020-09-11 12:27:26 -04001136 this->writeOpCode(SpvOpConstantComposite, 3 + type.columns(), fConstantBuffer);
1137 this->writeWord(typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001138 this->writeWord(result, fConstantBuffer);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001139 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001140 this->writeWord(arguments[0], fConstantBuffer);
1141 }
1142 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001143 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.arguments().size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001144 fConstantBuffer);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001145 this->writeWord(typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001146 this->writeWord(result, fConstantBuffer);
1147 for (SpvId id : arguments) {
1148 this->writeWord(id, fConstantBuffer);
1149 }
1150 }
1151 return result;
1152}
1153
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001154SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001155 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001156 SkASSERT(c.arguments().size() == 1);
1157 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001158 SkASSERT(constructorType.isFloat());
1159 SkASSERT(argType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001160 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001161 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001162 if (argType.isSigned()) {
1163 this->writeInstruction(SpvOpConvertSToF, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001164 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001165 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001166 SkASSERT(argType.isUnsigned());
1167 this->writeInstruction(SpvOpConvertUToF, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001168 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001169 }
1170 return result;
1171}
1172
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001173SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001174 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001175 SkASSERT(c.arguments().size() == 1);
1176 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001177 SkASSERT(constructorType.isSigned());
1178 SkASSERT(argType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001179 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001180 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001181 if (argType.isFloat()) {
1182 this->writeInstruction(SpvOpConvertFToS, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001183 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001184 }
1185 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001186 SkASSERT(argType.isUnsigned());
1187 this->writeInstruction(SpvOpBitcast, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001188 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001189 }
1190 return result;
1191}
1192
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001193SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001194 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001195 SkASSERT(c.arguments().size() == 1);
1196 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001197 SkASSERT(constructorType.isUnsigned());
1198 SkASSERT(argType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001199 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001200 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001201 if (argType.isFloat()) {
1202 this->writeInstruction(SpvOpConvertFToU, this->getType(constructorType), result, parameter,
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001203 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001204 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001205 SkASSERT(argType.isSigned());
1206 this->writeInstruction(SpvOpBitcast, this->getType(constructorType), result, parameter,
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001207 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001208 }
1209 return result;
1210}
1211
Ethan Nicholas84645e32017-02-09 13:57:14 -05001212void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001213 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001214 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001215 SpvId zeroId = this->writeFloatLiteral(zero);
1216 std::vector<SpvId> columnIds;
1217 for (int column = 0; column < type.columns(); column++) {
1218 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1219 out);
1220 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1221 out);
1222 SpvId columnId = this->nextId();
1223 this->writeWord(columnId, out);
1224 columnIds.push_back(columnId);
1225 for (int row = 0; row < type.columns(); row++) {
1226 this->writeWord(row == column ? diagonal : zeroId, out);
1227 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001228 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001229 }
1230 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1231 out);
1232 this->writeWord(this->getType(type), out);
1233 this->writeWord(id, out);
John Stilesf621e232020-08-25 13:33:02 -04001234 for (SpvId columnId : columnIds) {
1235 this->writeWord(columnId, out);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001236 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001237 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001238}
1239
1240void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001241 const Type& dstType, OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05001242 SkASSERT(srcType.isMatrix());
1243 SkASSERT(dstType.isMatrix());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001244 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001245 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1246 srcType.rows(),
1247 1));
1248 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1249 dstType.rows(),
1250 1));
1251 SpvId zeroId;
1252 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001253 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001254 zeroId = this->writeFloatLiteral(zero);
1255 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001256 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001257 zeroId = this->writeIntLiteral(zero);
1258 } else {
1259 ABORT("unsupported matrix component type");
1260 }
1261 SpvId zeroColumn = 0;
1262 SpvId columns[4];
1263 for (int i = 0; i < dstType.columns(); i++) {
1264 if (i < srcType.columns()) {
1265 // we're still inside the src matrix, copy the column
1266 SpvId srcColumn = this->nextId();
1267 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001268 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001269 SpvId dstColumn;
1270 if (srcType.rows() == dstType.rows()) {
1271 // columns are equal size, don't need to do anything
1272 dstColumn = srcColumn;
1273 }
1274 else if (dstType.rows() > srcType.rows()) {
1275 // dst column is bigger, need to zero-pad it
1276 dstColumn = this->nextId();
1277 int delta = dstType.rows() - srcType.rows();
1278 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1279 this->writeWord(dstColumnType, out);
1280 this->writeWord(dstColumn, out);
1281 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001282 for (int j = 0; j < delta; ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001283 this->writeWord(zeroId, out);
1284 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001285 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001286 }
1287 else {
1288 // dst column is smaller, need to swizzle the src column
1289 dstColumn = this->nextId();
1290 int count = dstType.rows();
1291 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1292 this->writeWord(dstColumnType, out);
1293 this->writeWord(dstColumn, out);
1294 this->writeWord(srcColumn, out);
1295 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001296 for (int j = 0; j < count; j++) {
1297 this->writeWord(j, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001298 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001299 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001300 }
1301 columns[i] = dstColumn;
1302 } else {
1303 // we're past the end of the src matrix, need a vector of zeroes
1304 if (!zeroColumn) {
1305 zeroColumn = this->nextId();
1306 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1307 this->writeWord(dstColumnType, out);
1308 this->writeWord(zeroColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001309 for (int j = 0; j < dstType.rows(); ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001310 this->writeWord(zeroId, out);
1311 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001312 this->writePrecisionModifier(dstType, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001313 }
1314 columns[i] = zeroColumn;
1315 }
1316 }
1317 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1318 this->writeWord(this->getType(dstType), out);
1319 this->writeWord(id, out);
1320 for (int i = 0; i < dstType.columns(); i++) {
1321 this->writeWord(columns[i], out);
1322 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001323 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001324}
1325
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001326void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1327 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001328 std::vector<SpvId>* columnIds,
1329 int* currentCount, int rows, SpvId entry,
1330 OutputStream& out) {
1331 SkASSERT(*currentCount < rows);
1332 ++(*currentCount);
1333 currentColumn->push_back(entry);
1334 if (*currentCount == rows) {
1335 *currentCount = 0;
1336 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1337 this->writeWord(columnType, out);
1338 SpvId columnId = this->nextId();
1339 this->writeWord(columnId, out);
1340 columnIds->push_back(columnId);
1341 for (SpvId id : *currentColumn) {
1342 this->writeWord(id, out);
1343 }
1344 currentColumn->clear();
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001345 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001346 }
1347}
1348
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001349SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001350 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001351 SkASSERT(type.isMatrix());
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001352 SkASSERT(c.arguments().size() > 0);
1353 const Type& arg0Type = c.arguments()[0]->type();
ethannicholasb3058bd2016-07-01 08:22:01 -07001354 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1355 // an instruction
1356 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001357 for (size_t i = 0; i < c.arguments().size(); i++) {
1358 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001359 }
1360 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001361 int rows = type.rows();
1362 int columns = type.columns();
John Stiles9aeed132020-11-24 17:36:06 -05001363 if (arguments.size() == 1 && arg0Type.isScalar()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001364 this->writeUniformScaleMatrix(result, arguments[0], type, out);
John Stiles9aeed132020-11-24 17:36:06 -05001365 } else if (arguments.size() == 1 && arg0Type.isMatrix()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001366 this->writeMatrixCopy(result, arguments[0], arg0Type, type, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001367 } else if (arguments.size() == 1 &&
John Stiles9aeed132020-11-24 17:36:06 -05001368 arg0Type.isVector()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001369 SkASSERT(type.rows() == 2 && type.columns() == 2);
1370 SkASSERT(arg0Type.columns() == 4);
1371 SpvId componentType = this->getType(type.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001372 SpvId v[4];
1373 for (int i = 0; i < 4; ++i) {
1374 v[i] = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001375 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i,
1376 out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001377 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001378 SpvId columnType = this->getType(type.componentType().toCompound(fContext, 2, 1));
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001379 SpvId column1 = this->nextId();
1380 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1381 SpvId column2 = this->nextId();
1382 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001383 this->writeInstruction(SpvOpCompositeConstruct, this->getType(type), result, column1,
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001384 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001385 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001386 SpvId columnType = this->getType(type.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001387 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001388 // ids of vectors and scalars we have written to the current column so far
1389 std::vector<SpvId> currentColumn;
1390 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001391 int currentCount = 0;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001392 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001393 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001394 const Type& argType = c.arguments()[i]->type();
John Stiles9aeed132020-11-24 17:36:06 -05001395 if (currentCount == 0 && argType.isVector() &&
Ethan Nicholas30d30222020-09-11 12:27:26 -04001396 argType.columns() == type.rows()) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001397 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001398 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001399 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001400 if (argType.columns() == 1) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001401 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1402 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001403 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001404 SpvId componentType = this->getType(argType.componentType());
1405 for (int j = 0; j < argType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001406 SpvId swizzle = this->nextId();
1407 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1408 arguments[i], j, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001409 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1410 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001411 }
1412 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001413 }
1414 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001415 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001416 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001417 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001418 this->writeWord(result, out);
1419 for (SpvId id : columnIds) {
1420 this->writeWord(id, out);
1421 }
1422 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001423 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001424 return result;
1425}
1426
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001427SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001428 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001429 SkASSERT(type.isVector());
Brian Osmanb6b95732020-06-30 11:44:27 -04001430 if (c.isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001431 return this->writeConstantVector(c);
1432 }
1433 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1434 // an instruction
1435 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001436 for (size_t i = 0; i < c.arguments().size(); i++) {
1437 const Type& argType = c.arguments()[i]->type();
John Stiles9aeed132020-11-24 17:36:06 -05001438 if (argType.isVector()) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001439 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1440 // extract the components and convert them in that case manually. On top of that,
1441 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1442 // doesn't handle vector arguments at all, so we always extract vector components and
1443 // pass them into OpCreateComposite individually.
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001444 SpvId vec = this->writeExpression(*c.arguments()[i], out);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001445 SpvOp_ op = SpvOpUndef;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001446 const Type& src = argType.componentType();
1447 const Type& dst = type.componentType();
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001448 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1449 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001450 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001451 return vec;
1452 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001453 } else if (src == *fContext.fInt_Type ||
1454 src == *fContext.fShort_Type ||
1455 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001456 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001457 } else if (src == *fContext.fUInt_Type ||
1458 src == *fContext.fUShort_Type ||
1459 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001460 op = SpvOpConvertUToF;
1461 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001462 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001463 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001464 } else if (dst == *fContext.fInt_Type ||
1465 dst == *fContext.fShort_Type ||
1466 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001467 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1468 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001469 } else if (src == *fContext.fInt_Type ||
1470 src == *fContext.fShort_Type ||
1471 src == *fContext.fByte_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001472 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001473 return vec;
1474 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001475 } else if (src == *fContext.fUInt_Type ||
1476 src == *fContext.fUShort_Type ||
1477 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001478 op = SpvOpBitcast;
1479 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001480 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001481 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001482 } else if (dst == *fContext.fUInt_Type ||
1483 dst == *fContext.fUShort_Type ||
1484 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001485 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1486 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001487 } else if (src == *fContext.fInt_Type ||
1488 src == *fContext.fShort_Type ||
1489 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001490 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001491 } else if (src == *fContext.fUInt_Type ||
1492 src == *fContext.fUShort_Type ||
1493 src == *fContext.fUByte_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001494 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001495 return vec;
1496 }
1497 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001498 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001499 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001500 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001501 for (int j = 0; j < argType.columns(); j++) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001502 SpvId swizzle = this->nextId();
1503 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1504 out);
1505 if (op != SpvOpUndef) {
1506 SpvId cast = this->nextId();
1507 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1508 arguments.push_back(cast);
1509 } else {
1510 arguments.push_back(swizzle);
1511 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001512 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001513 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001514 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001515 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001516 }
1517 SpvId result = this->nextId();
John Stiles9aeed132020-11-24 17:36:06 -05001518 if (arguments.size() == 1 && c.arguments()[0]->type().isScalar()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001519 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(), out);
1520 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001521 this->writeWord(result, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001522 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001523 this->writeWord(arguments[0], out);
1524 }
1525 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001526 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001527 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001528 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001529 this->writeWord(result, out);
1530 for (SpvId id : arguments) {
1531 this->writeWord(id, out);
1532 }
1533 }
1534 return result;
1535}
1536
Ethan Nicholasbd553222017-07-18 15:54:59 -04001537SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001538 const Type& type = c.type();
John Stilesc0c51062020-12-03 17:16:29 -05001539 SkASSERT(type.isArray());
Ethan Nicholasbd553222017-07-18 15:54:59 -04001540 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1541 // an instruction
1542 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001543 for (size_t i = 0; i < c.arguments().size(); i++) {
1544 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholasbd553222017-07-18 15:54:59 -04001545 }
1546 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001547 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.arguments().size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001548 this->writeWord(this->getType(type), out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001549 this->writeWord(result, out);
1550 for (SpvId id : arguments) {
1551 this->writeWord(id, out);
1552 }
1553 return result;
1554}
1555
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001556SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001557 const Type& type = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001558 if (c.arguments().size() == 1 &&
1559 this->getActualType(type) == this->getActualType(c.arguments()[0]->type())) {
1560 return this->writeExpression(*c.arguments()[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001561 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001562 if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001563 return this->writeFloatConstructor(c, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001564 } else if (type == *fContext.fInt_Type ||
1565 type == *fContext.fShort_Type ||
1566 type == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001567 return this->writeIntConstructor(c, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001568 } else if (type == *fContext.fUInt_Type ||
1569 type == *fContext.fUShort_Type ||
1570 type == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001571 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001572 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001573 switch (type.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001574 case Type::TypeKind::kVector:
ethannicholasb3058bd2016-07-01 08:22:01 -07001575 return this->writeVectorConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001576 case Type::TypeKind::kMatrix:
ethannicholasb3058bd2016-07-01 08:22:01 -07001577 return this->writeMatrixConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001578 case Type::TypeKind::kArray:
Ethan Nicholasbd553222017-07-18 15:54:59 -04001579 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001580 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001581#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07001582 ABORT("unsupported constructor: %s", c.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001583#endif
1584 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001585 }
1586}
1587
1588SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1589 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001590 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001591 return SpvStorageClassInput;
1592 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001593 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001594 return SpvStorageClassOutput;
1595 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001596 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001597 return SpvStorageClassPushConstant;
1598 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001599 return SpvStorageClassUniform;
1600 } else {
1601 return SpvStorageClassFunction;
1602 }
1603}
1604
ethannicholasf789b382016-08-03 12:43:36 -07001605SpvStorageClass_ get_storage_class(const Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001606 switch (expr.kind()) {
1607 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -04001608 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001609 if (var.storage() != Variable::Storage::kGlobal) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001610 return SpvStorageClassFunction;
1611 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001612 SpvStorageClass_ result = get_storage_class(var.modifiers());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001613 if (result == SpvStorageClassFunction) {
1614 result = SpvStorageClassPrivate;
1615 }
1616 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001617 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001618 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001619 return get_storage_class(*expr.as<FieldAccess>().base());
Ethan Nicholase6592142020-09-08 10:22:09 -04001620 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001621 return get_storage_class(*expr.as<IndexExpression>().base());
ethannicholasb3058bd2016-07-01 08:22:01 -07001622 default:
1623 return SpvStorageClassFunction;
1624 }
1625}
1626
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001627std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001628 std::vector<SpvId> chain;
Ethan Nicholase6592142020-09-08 10:22:09 -04001629 switch (expr.kind()) {
1630 case Expression::Kind::kIndex: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001631 IndexExpression& indexExpr = (IndexExpression&) expr;
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001632 chain = this->getAccessChain(*indexExpr.base(), out);
1633 chain.push_back(this->writeExpression(*indexExpr.index(), out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001634 break;
1635 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001636 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001637 FieldAccess& fieldExpr = (FieldAccess&) expr;
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001638 chain = this->getAccessChain(*fieldExpr.base(), out);
1639 IntLiteral index(fContext, -1, fieldExpr.fieldIndex());
ethannicholasb3058bd2016-07-01 08:22:01 -07001640 chain.push_back(this->writeIntLiteral(index));
1641 break;
1642 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001643 default: {
1644 SpvId id = this->getLValue(expr, out)->getPointer();
1645 SkASSERT(id != 0);
1646 chain.push_back(id);
1647 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001648 }
1649 return chain;
1650}
1651
1652class PointerLValue : public SPIRVCodeGenerator::LValue {
1653public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001654 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1655 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001656 : fGen(gen)
1657 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001658 , fType(type)
1659 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001660
John Stiles1cf2c8d2020-08-13 22:58:04 -04001661 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001662 return fPointer;
1663 }
1664
John Stiles1cf2c8d2020-08-13 22:58:04 -04001665 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001666 SpvId result = fGen.nextId();
1667 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001668 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001669 return result;
1670 }
1671
John Stiles1cf2c8d2020-08-13 22:58:04 -04001672 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001673 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1674 }
1675
1676private:
1677 SPIRVCodeGenerator& fGen;
1678 const SpvId fPointer;
1679 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001680 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001681};
1682
1683class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1684public:
John Stiles750109b2020-10-30 13:45:46 -04001685 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const ComponentArray& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001686 const Type& baseType, const Type& swizzleType,
1687 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001688 : fGen(gen)
1689 , fVecPointer(vecPointer)
1690 , fComponents(components)
1691 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001692 , fSwizzleType(swizzleType)
1693 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001694
John Stiles1cf2c8d2020-08-13 22:58:04 -04001695 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001696 return 0;
1697 }
1698
John Stiles1cf2c8d2020-08-13 22:58:04 -04001699 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001700 SpvId base = fGen.nextId();
1701 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001702 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001703 SpvId result = fGen.nextId();
1704 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1705 fGen.writeWord(fGen.getType(fSwizzleType), out);
1706 fGen.writeWord(result, out);
1707 fGen.writeWord(base, out);
1708 fGen.writeWord(base, out);
1709 for (int component : fComponents) {
1710 fGen.writeWord(component, out);
1711 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001712 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001713 return result;
1714 }
1715
John Stiles1cf2c8d2020-08-13 22:58:04 -04001716 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001717 // use OpVectorShuffle to mix and match the vector components. We effectively create
1718 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001719 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001720 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001721 // float3L = ...;
1722 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001723 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001724 // 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 -07001725 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1726 // (3, 1, 4).
1727 SpvId base = fGen.nextId();
1728 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1729 SpvId shuffle = fGen.nextId();
1730 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1731 fGen.writeWord(fGen.getType(fBaseType), out);
1732 fGen.writeWord(shuffle, out);
1733 fGen.writeWord(base, out);
1734 fGen.writeWord(value, out);
1735 for (int i = 0; i < fBaseType.columns(); i++) {
1736 // current offset into the virtual vector, defaults to pulling the unmodified
1737 // value from the left side
1738 int offset = i;
1739 // check to see if we are writing this component
1740 for (size_t j = 0; j < fComponents.size(); j++) {
1741 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001742 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001743 // the correct component of the right side instead of preserving the
1744 // value from the left
1745 offset = (int) (j + fBaseType.columns());
1746 break;
1747 }
1748 }
1749 fGen.writeWord(offset, out);
1750 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001751 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001752 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1753 }
1754
1755private:
1756 SPIRVCodeGenerator& fGen;
1757 const SpvId fVecPointer;
John Stiles750109b2020-10-30 13:45:46 -04001758 const ComponentArray& fComponents;
ethannicholasb3058bd2016-07-01 08:22:01 -07001759 const Type& fBaseType;
1760 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001761 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001762};
1763
Greg Daniel64773e62016-11-22 09:44:03 -05001764std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001765 OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001766 const Type& type = expr.type();
1767 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
Ethan Nicholase6592142020-09-08 10:22:09 -04001768 switch (expr.kind()) {
1769 case Expression::Kind::kVariableReference: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001770 SpvId typeId;
Ethan Nicholas78686922020-10-08 06:46:27 -04001771 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001772 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001773 typeId = this->getType(Type("sk_in", Type::TypeKind::kArray,
1774 var.type().componentType(), fSkInCount));
Ethan Nicholas5226b772018-05-03 16:20:41 -04001775 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001776 typeId = this->getType(type);
Ethan Nicholas5226b772018-05-03 16:20:41 -04001777 }
ethannicholasd598f792016-07-25 10:08:54 -07001778 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001779 SkASSERT(entry != fVariableMap.end());
John Stiles5570c512020-11-19 17:58:07 -05001780 return std::make_unique<PointerLValue>(*this, entry->second, typeId, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001781 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001782 case Expression::Kind::kIndex: // fall through
1783 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001784 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1785 SpvId member = this->nextId();
1786 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001787 this->writeWord(this->getPointerType(type, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001788 this->writeWord(member, out);
1789 for (SpvId idx : chain) {
1790 this->writeWord(idx, out);
1791 }
John Stiles5570c512020-11-19 17:58:07 -05001792 return std::make_unique<PointerLValue>(*this, member, this->getType(type), precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001793 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001794 case Expression::Kind::kSwizzle: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001795 Swizzle& swizzle = (Swizzle&) expr;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001796 size_t count = swizzle.components().size();
1797 SpvId base = this->getLValue(*swizzle.base(), out)->getPointer();
John Stiles5570c512020-11-19 17:58:07 -05001798 if (!base) {
1799 fErrors.error(swizzle.fOffset, "unable to retrieve lvalue from swizzle");
1800 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001801 if (count == 1) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001802 IntLiteral index(fContext, -1, swizzle.components()[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001803 SpvId member = this->nextId();
1804 this->writeInstruction(SpvOpAccessChain,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001805 this->getPointerType(type,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001806 get_storage_class(*swizzle.base())),
Greg Daniel64773e62016-11-22 09:44:03 -05001807 member,
1808 base,
1809 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001810 out);
John Stiles5570c512020-11-19 17:58:07 -05001811 return std::make_unique<PointerLValue>(*this, member, this->getType(type),
1812 precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001813 } else {
John Stiles5570c512020-11-19 17:58:07 -05001814 return std::make_unique<SwizzleLValue>(*this, base, swizzle.components(),
1815 swizzle.base()->type(), type, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001816 }
1817 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001818 case Expression::Kind::kTernary: {
Ethan Nicholasa583b812018-01-18 13:32:11 -05001819 TernaryExpression& t = (TernaryExpression&) expr;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001820 SpvId test = this->writeExpression(*t.test(), out);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001821 SpvId end = this->nextId();
1822 SpvId ifTrueLabel = this->nextId();
1823 SpvId ifFalseLabel = this->nextId();
1824 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1825 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1826 this->writeLabel(ifTrueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04001827 SpvId ifTrue = this->getLValue(*t.ifTrue(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001828 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001829 this->writeInstruction(SpvOpBranch, end, out);
1830 ifTrueLabel = fCurrentBlock;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001831 SpvId ifFalse = this->getLValue(*t.ifFalse(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001832 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001833 ifFalseLabel = fCurrentBlock;
1834 this->writeInstruction(SpvOpBranch, end, out);
1835 SpvId result = this->nextId();
1836 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1837 ifTrueLabel, ifFalse, ifFalseLabel, out);
John Stiles5570c512020-11-19 17:58:07 -05001838 return std::make_unique<PointerLValue>(*this, result, this->getType(type), precision);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001839 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001840 default: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001841 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001842 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001843 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1844 // caught by IRGenerator
1845 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001846 SpvId pointerType = this->getPointerType(type, SpvStorageClassFunction);
1847 this->writeInstruction(SpvOpVariable, pointerType, result, SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001848 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001849 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
John Stiles5570c512020-11-19 17:58:07 -05001850 return std::make_unique<PointerLValue>(*this, result, this->getType(type), precision);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001851 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001852 }
1853}
1854
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001855SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001856 SpvId result = this->nextId();
Ethan Nicholas78686922020-10-08 06:46:27 -04001857 auto entry = fVariableMap.find(ref.variable());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001858 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001859 SpvId var = entry->second;
Ethan Nicholas78686922020-10-08 06:46:27 -04001860 this->writeInstruction(SpvOpLoad, this->getType(ref.variable()->type()), result, var, out);
1861 this->writePrecisionModifier(ref.variable()->type(), result);
1862 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
Greg Daniela85e4bf2020-06-17 16:32:45 -04001863 (fProgram.fSettings.fFlipY || fProgram.fSettings.fInverseW)) {
1864 // The x component never changes, so just grab it
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001865 SpvId xId = this->nextId();
1866 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1867 result, 0, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001868
1869 // Calculate the y component which may need to be flipped
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001870 SpvId rawYId = this->nextId();
1871 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1872 result, 1, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001873 SpvId flippedYId = 0;
1874 if (fProgram.fSettings.fFlipY) {
1875 // need to remap to a top-left coordinate system
1876 if (fRTHeightStructId == (SpvId)-1) {
1877 // height variable hasn't been written yet
Greg Daniela85e4bf2020-06-17 16:32:45 -04001878 SkASSERT(fRTHeightFieldIndex == (SpvId)-1);
1879 std::vector<Type::Field> fields;
John Stiles5570c512020-11-19 17:58:07 -05001880 if (fProgram.fSettings.fRTHeightOffset < 0) {
1881 fErrors.error(ref.fOffset, "RTHeightOffset is negative");
1882 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001883 fields.emplace_back(
1884 Modifiers(Layout(0, -1, fProgram.fSettings.fRTHeightOffset, -1, -1, -1, -1,
1885 -1, Layout::Format::kUnspecified,
1886 Layout::kUnspecified_Primitive, 1, -1, "", "",
1887 Layout::kNo_Key, Layout::CType::kDefault),
1888 0),
1889 SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1890 StringFragment name("sksl_synthetic_uniforms");
1891 Type intfStruct(-1, name, fields);
1892
1893 int binding = fProgram.fSettings.fRTHeightBinding;
John Stiles5570c512020-11-19 17:58:07 -05001894 if (binding == -1) {
1895 fErrors.error(ref.fOffset, "layout(binding=...) is required in SPIR-V");
1896 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001897 int set = fProgram.fSettings.fRTHeightSet;
John Stiles5570c512020-11-19 17:58:07 -05001898 if (set == -1) {
1899 fErrors.error(ref.fOffset, "layout(set=...) is required in SPIR-V");
1900 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001901 Layout layout(0, -1, -1, binding, -1, set, -1, -1, Layout::Format::kUnspecified,
1902 Layout::kUnspecified_Primitive, -1, -1, "", "", Layout::kNo_Key,
1903 Layout::CType::kDefault);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001904 Modifiers modifiers(layout, Modifiers::kUniform_Flag);
John Stiles3ae071e2020-08-05 15:29:29 -04001905 const Variable* intfVar = fSynthetics.takeOwnershipOfSymbol(
1906 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -05001907 fProgram.fModifiers->addToPool(modifiers),
John Stiles3ae071e2020-08-05 15:29:29 -04001908 name,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001909 &intfStruct,
Brian Osman3887a012020-09-30 13:22:27 -04001910 /*builtin=*/false,
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001911 Variable::Storage::kGlobal));
John Stilesd39aec02020-12-03 10:42:26 -05001912 InterfaceBlock intf(/*offset=*/-1, intfVar, name,
1913 /*instanceName=*/"", /*arraySize=*/0,
John Stiles7c3515b2020-10-16 18:38:39 -04001914 std::make_shared<SymbolTable>(&fErrors, /*builtin=*/false));
Stephen White88574972020-06-23 19:09:29 -04001915
1916 fRTHeightStructId = this->writeInterfaceBlock(intf, false);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001917 fRTHeightFieldIndex = 0;
Jim Van Verthf3ec9832020-10-21 16:09:57 -04001918 fRTHeightStorageClass = SpvStorageClassUniform;
Greg Daniela85e4bf2020-06-17 16:32:45 -04001919 }
1920 SkASSERT(fRTHeightFieldIndex != (SpvId)-1);
1921
1922 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1923 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1924 SpvId heightPtr = this->nextId();
1925 this->writeOpCode(SpvOpAccessChain, 5, out);
Jim Van Verthf3ec9832020-10-21 16:09:57 -04001926 this->writeWord(this->getPointerType(*fContext.fFloat_Type, fRTHeightStorageClass),
Greg Daniela85e4bf2020-06-17 16:32:45 -04001927 out);
1928 this->writeWord(heightPtr, out);
1929 this->writeWord(fRTHeightStructId, out);
1930 this->writeWord(fieldIndexId, out);
1931 SpvId heightRead = this->nextId();
1932 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1933 heightPtr, out);
1934
1935 flippedYId = this->nextId();
1936 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
1937 heightRead, rawYId, out);
1938 }
1939
1940 // The z component will always be zero so we just get an id to the 0 literal
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001941 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001942 SpvId zeroId = writeFloatLiteral(zero);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001943
1944 // Calculate the w component which may need to be inverted
1945 SpvId rawWId = this->nextId();
1946 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawWId,
Ethan Nicholas20798e52018-12-04 12:30:50 -05001947 result, 3, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001948 SpvId invWId = 0;
1949 if (fProgram.fSettings.fInverseW) {
1950 // We need to invert w
1951 FloatLiteral one(fContext, -1, 1.0);
1952 SpvId oneId = writeFloatLiteral(one);
1953 invWId = this->nextId();
1954 this->writeInstruction(SpvOpFDiv, this->getType(*fContext.fFloat_Type), invWId, oneId,
1955 rawWId, out);
1956 }
1957
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);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001970 if (fProgram.fSettings.fInverseW) {
1971 this->writeWord(invWId, out);
1972 } else {
1973 this->writeWord(rawWId, out);
1974 }
1975
1976 return adjusted;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001977 }
Ethan Nicholas78686922020-10-08 06:46:27 -04001978 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
Chris Daltonb91c4662018-08-01 10:46:22 -06001979 !fProgram.fSettings.fFlipY) {
1980 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1981 // the default convention of "counter-clockwise face is front".
1982 SpvId inverse = this->nextId();
1983 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1984 result, out);
1985 return inverse;
1986 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001987 return result;
1988}
1989
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001990SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05001991 if (expr.base()->type().isVector()) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001992 SpvId base = this->writeExpression(*expr.base(), out);
1993 SpvId index = this->writeExpression(*expr.index(), out);
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001994 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001995 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.type()), result, base,
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001996 index, out);
1997 return result;
1998 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001999 return getLValue(expr, out)->load(out);
2000}
2001
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002002SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002003 return getLValue(f, out)->load(out);
2004}
2005
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002006SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002007 SpvId base = this->writeExpression(*swizzle.base(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002008 SpvId result = this->nextId();
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002009 size_t count = swizzle.components().size();
ethannicholasb3058bd2016-07-01 08:22:01 -07002010 if (count == 1) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002011 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.type()), result, base,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002012 swizzle.components()[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002013 } else {
2014 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002015 this->writeWord(this->getType(swizzle.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002016 this->writeWord(result, out);
2017 this->writeWord(base, out);
Brian Osman25647672020-09-15 15:16:56 -04002018 this->writeWord(base, out);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002019 for (int component : swizzle.components()) {
Brian Osman25647672020-09-15 15:16:56 -04002020 this->writeWord(component, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002021 }
2022 }
2023 return result;
2024}
2025
Greg Daniel64773e62016-11-22 09:44:03 -05002026SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
2027 const Type& operandType, SpvId lhs,
2028 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002029 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002030 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002031 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002032 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002033 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002034 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002035 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002036 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
John Stiles123501f2020-12-09 10:08:13 -05002037 } else if (is_bool(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002038 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002039 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07002040 } else {
John Stiles123501f2020-12-09 10:08:13 -05002041 fErrors.error(operandType.fOffset,
2042 "unsupported operand for binary expression: " + operandType.description());
2043 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002044 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04002045 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002046 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
2047 fDecorationBuffer);
2048 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002049 return result;
2050}
2051
Ethan Nicholas48e24052018-03-14 13:51:39 -04002052SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
2053 OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05002054 if (operandType.isVector()) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002055 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04002056 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002057 return result;
2058 }
2059 return id;
2060}
2061
Ethan Nicholas68990be2017-07-13 09:36:52 -04002062SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
2063 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002064 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04002065 OutputStream& out) {
2066 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
John Stiles9aeed132020-11-24 17:36:06 -05002067 SkASSERT(operandType.isMatrix());
Ethan Nicholas0df21132018-07-10 09:37:51 -04002068 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2069 operandType.rows(),
2070 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04002071 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002072 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04002073 1));
2074 SpvId boolType = this->getType(*fContext.fBool_Type);
2075 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04002076 for (int i = 0; i < operandType.columns(); i++) {
2077 SpvId columnL = this->nextId();
2078 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2079 SpvId columnR = this->nextId();
2080 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002081 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002082 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
2083 SpvId merge = this->nextId();
2084 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002085 if (result != 0) {
2086 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002087 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002088 result = next;
2089 }
2090 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002091 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04002092 }
2093 }
2094 return result;
2095}
2096
Ethan Nicholas0df21132018-07-10 09:37:51 -04002097SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
2098 SpvId rhs, SpvOp_ floatOperator,
2099 SpvOp_ intOperator,
2100 OutputStream& out) {
2101 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
John Stiles9aeed132020-11-24 17:36:06 -05002102 SkASSERT(operandType.isMatrix());
Ethan Nicholas0df21132018-07-10 09:37:51 -04002103 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2104 operandType.rows(),
2105 1));
2106 SpvId columns[4];
2107 for (int i = 0; i < operandType.columns(); i++) {
2108 SpvId columnL = this->nextId();
2109 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2110 SpvId columnR = this->nextId();
2111 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2112 columns[i] = this->nextId();
2113 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2114 }
2115 SpvId result = this->nextId();
2116 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2117 this->writeWord(this->getType(operandType), out);
2118 this->writeWord(result, out);
2119 for (int i = 0; i < operandType.columns(); i++) {
2120 this->writeWord(columns[i], out);
2121 }
2122 return result;
2123}
2124
Ethan Nicholas49465b42019-04-17 12:22:21 -04002125std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2126 if (type.isInteger()) {
2127 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002128 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002129 else if (type.isFloat()) {
2130 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002131 } else {
Ethan Nicholase2c49992020-10-05 11:49:11 -04002132 ABORT("math is unsupported on type '%s'", String(type.name()).c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002133 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002134}
2135
2136SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Token::Kind op,
2137 const Type& rightType, SpvId rhs,
2138 const Type& resultType, OutputStream& out) {
John Stilesd0614f22020-12-09 11:11:41 -05002139 // The comma operator ignores the type of the left-hand side entirely.
2140 if (op == Token::Kind::TK_COMMA) {
2141 return rhs;
2142 }
Ethan Nicholas48e24052018-03-14 13:51:39 -04002143 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002144 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002145 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2146 // handling in SPIR-V
Ethan Nicholas49465b42019-04-17 12:22:21 -04002147 if (this->getActualType(leftType) != this->getActualType(rightType)) {
John Stiles9aeed132020-11-24 17:36:06 -05002148 if (leftType.isVector() && rightType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002149 if (op == Token::Kind::TK_SLASH) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002150 SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
2151 SpvId inverse = this->nextId();
2152 this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
2153 rhs = inverse;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002154 op = Token::Kind::TK_STAR;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002155 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002156 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002157 SpvId result = this->nextId();
2158 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2159 result, lhs, rhs, out);
2160 return result;
2161 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002162 // promote number to vector
2163 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002164 const Type& vecType = leftType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002165 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2166 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002167 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002168 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002169 this->writeWord(rhs, out);
2170 }
2171 rhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002172 operandType = &leftType;
John Stiles9aeed132020-11-24 17:36:06 -05002173 } else if (rightType.isVector() && leftType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002174 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002175 SpvId result = this->nextId();
2176 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2177 result, rhs, lhs, out);
2178 return result;
2179 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002180 // promote number to vector
2181 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002182 const Type& vecType = rightType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002183 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2184 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002185 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002186 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002187 this->writeWord(lhs, out);
2188 }
2189 lhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002190 operandType = &rightType;
John Stiles9aeed132020-11-24 17:36:06 -05002191 } else if (leftType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002192 SpvOp_ spvop;
John Stiles9aeed132020-11-24 17:36:06 -05002193 if (rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002194 spvop = SpvOpMatrixTimesMatrix;
John Stiles9aeed132020-11-24 17:36:06 -05002195 } else if (rightType.isVector()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002196 spvop = SpvOpMatrixTimesVector;
ethannicholasb3058bd2016-07-01 08:22:01 -07002197 } else {
John Stiles9aeed132020-11-24 17:36:06 -05002198 SkASSERT(rightType.isScalar());
Ethan Nicholas49465b42019-04-17 12:22:21 -04002199 spvop = SpvOpMatrixTimesScalar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002200 }
2201 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002202 this->writeInstruction(spvop, this->getType(resultType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002203 return result;
John Stiles9aeed132020-11-24 17:36:06 -05002204 } else if (rightType.isMatrix()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002205 SpvId result = this->nextId();
John Stiles9aeed132020-11-24 17:36:06 -05002206 if (leftType.isVector()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002207 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(resultType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002208 lhs, rhs, out);
2209 } else {
John Stiles9aeed132020-11-24 17:36:06 -05002210 SkASSERT(leftType.isScalar());
Ethan Nicholas49465b42019-04-17 12:22:21 -04002211 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(resultType), result,
2212 rhs, lhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002213 }
2214 return result;
2215 } else {
John Stilesd8ca6b62020-11-23 14:28:36 -05002216 fErrors.error(leftType.fOffset, "unsupported mixed-type expression");
Ethan Nicholas49465b42019-04-17 12:22:21 -04002217 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002218 }
2219 } else {
John Stiles2d4f9592020-10-30 10:29:12 -04002220 operandType = &this->getActualType(leftType);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002221 SkASSERT(*operandType == this->getActualType(rightType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002222 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002223 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002224 case Token::Kind::TK_EQEQ: {
John Stiles9aeed132020-11-24 17:36:06 -05002225 if (operandType->isMatrix()) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002226 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002227 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002228 }
John Stiles4a7dc462020-11-25 11:08:08 -05002229 SkASSERT(resultType.isBoolean());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002230 const Type* tmpType;
John Stiles9aeed132020-11-24 17:36:06 -05002231 if (operandType->isVector()) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002232 tmpType = &fContext.fBool_Type->toCompound(fContext,
2233 operandType->columns(),
2234 operandType->rows());
2235 } else {
2236 tmpType = &resultType;
2237 }
2238 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002239 SpvOpFOrdEqual, SpvOpIEqual,
2240 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002241 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002242 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002243 case Token::Kind::TK_NEQ:
John Stiles9aeed132020-11-24 17:36:06 -05002244 if (operandType->isMatrix()) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002245 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002246 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002247 }
John Stiles4a7dc462020-11-25 11:08:08 -05002248 [[fallthrough]];
2249 case Token::Kind::TK_LOGICALXOR:
2250 SkASSERT(resultType.isBoolean());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002251 const Type* tmpType;
John Stiles9aeed132020-11-24 17:36:06 -05002252 if (operandType->isVector()) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002253 tmpType = &fContext.fBool_Type->toCompound(fContext,
2254 operandType->columns(),
2255 operandType->rows());
2256 } else {
2257 tmpType = &resultType;
2258 }
2259 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002260 SpvOpFOrdNotEqual, SpvOpINotEqual,
2261 SpvOpINotEqual, SpvOpLogicalNotEqual,
2262 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002263 *operandType, SpvOpAny, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002264 case Token::Kind::TK_GT:
John Stiles4a7dc462020-11-25 11:08:08 -05002265 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002266 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2267 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002268 SpvOpUGreaterThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002269 case Token::Kind::TK_LT:
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, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002272 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002273 case Token::Kind::TK_GTEQ:
John Stiles4a7dc462020-11-25 11:08:08 -05002274 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002275 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2276 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002277 SpvOpUGreaterThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002278 case Token::Kind::TK_LTEQ:
John Stiles4a7dc462020-11-25 11:08:08 -05002279 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002280 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2281 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002282 SpvOpULessThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002283 case Token::Kind::TK_PLUS:
John Stiles9aeed132020-11-24 17:36:06 -05002284 if (leftType.isMatrix() && rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002285 SkASSERT(leftType == rightType);
2286 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002287 SpvOpFAdd, SpvOpIAdd, out);
2288 }
Greg Daniel64773e62016-11-22 09:44:03 -05002289 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002290 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002291 case Token::Kind::TK_MINUS:
John Stiles9aeed132020-11-24 17:36:06 -05002292 if (leftType.isMatrix() && rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002293 SkASSERT(leftType == rightType);
2294 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002295 SpvOpFSub, SpvOpISub, out);
2296 }
Greg Daniel64773e62016-11-22 09:44:03 -05002297 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002298 SpvOpISub, SpvOpISub, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002299 case Token::Kind::TK_STAR:
John Stiles9aeed132020-11-24 17:36:06 -05002300 if (leftType.isMatrix() && rightType.isMatrix()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002301 // matrix multiply
2302 SpvId result = this->nextId();
2303 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2304 lhs, rhs, out);
2305 return result;
2306 }
Greg Daniel64773e62016-11-22 09:44:03 -05002307 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002308 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002309 case Token::Kind::TK_SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002310 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002311 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002312 case Token::Kind::TK_PERCENT:
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002313 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2314 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002315 case Token::Kind::TK_SHL:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002316 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2317 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2318 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002319 case Token::Kind::TK_SHR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002320 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2321 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2322 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002323 case Token::Kind::TK_BITWISEAND:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002324 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2325 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002326 case Token::Kind::TK_BITWISEOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002327 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2328 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002329 case Token::Kind::TK_BITWISEXOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002330 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2331 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002332 default:
John Stiles5570c512020-11-19 17:58:07 -05002333 fErrors.error(0, "unsupported token");
Ethan Nicholas49465b42019-04-17 12:22:21 -04002334 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002335 }
2336}
2337
Ethan Nicholas49465b42019-04-17 12:22:21 -04002338SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
John Stiles2d4f9592020-10-30 10:29:12 -04002339 const Expression& left = *b.left();
2340 const Expression& right = *b.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002341 Token::Kind op = b.getOperator();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002342 // handle cases where we don't necessarily evaluate both LHS and RHS
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002343 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002344 case Token::Kind::TK_EQ: {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002345 SpvId rhs = this->writeExpression(right, out);
2346 this->getLValue(left, out)->store(rhs, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002347 return rhs;
2348 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002349 case Token::Kind::TK_LOGICALAND:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002350 return this->writeLogicalAnd(b, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002351 case Token::Kind::TK_LOGICALOR:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002352 return this->writeLogicalOr(b, out);
2353 default:
2354 break;
2355 }
2356
2357 std::unique_ptr<LValue> lvalue;
2358 SpvId lhs;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002359 if (Compiler::IsAssignment(op)) {
2360 lvalue = this->getLValue(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002361 lhs = lvalue->load(out);
2362 } else {
2363 lvalue = nullptr;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002364 lhs = this->writeExpression(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002365 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002366 SpvId rhs = this->writeExpression(right, out);
2367 SpvId result = this->writeBinaryExpression(left.type(), lhs, Compiler::RemoveAssignment(op),
2368 right.type(), rhs, b.type(), out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002369 if (lvalue) {
2370 lvalue->store(result, out);
2371 }
2372 return result;
2373}
2374
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002375SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002376 SkASSERT(a.getOperator() == Token::Kind::TK_LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002377 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002378 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
John Stiles2d4f9592020-10-30 10:29:12 -04002379 SpvId lhs = this->writeExpression(*a.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002380 SpvId rhsLabel = this->nextId();
2381 SpvId end = this->nextId();
2382 SpvId lhsBlock = fCurrentBlock;
2383 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2384 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2385 this->writeLabel(rhsLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04002386 SpvId rhs = this->writeExpression(*a.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002387 SpvId rhsBlock = fCurrentBlock;
2388 this->writeInstruction(SpvOpBranch, end, out);
2389 this->writeLabel(end, out);
2390 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002391 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002392 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002393 return result;
2394}
2395
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002396SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002397 SkASSERT(o.getOperator() == Token::Kind::TK_LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002398 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002399 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
John Stiles2d4f9592020-10-30 10:29:12 -04002400 SpvId lhs = this->writeExpression(*o.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002401 SpvId rhsLabel = this->nextId();
2402 SpvId end = this->nextId();
2403 SpvId lhsBlock = fCurrentBlock;
2404 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2405 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2406 this->writeLabel(rhsLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04002407 SpvId rhs = this->writeExpression(*o.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002408 SpvId rhsBlock = fCurrentBlock;
2409 this->writeInstruction(SpvOpBranch, end, out);
2410 this->writeLabel(end, out);
2411 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002412 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002413 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002414 return result;
2415}
2416
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002417SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002418 const Type& type = t.type();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002419 SpvId test = this->writeExpression(*t.test(), out);
2420 if (t.ifTrue()->type().columns() == 1 &&
2421 t.ifTrue()->isCompileTimeConstant() &&
2422 t.ifFalse()->isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002423 // both true and false are constants, can just use OpSelect
2424 SpvId result = this->nextId();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002425 SpvId trueId = this->writeExpression(*t.ifTrue(), out);
2426 SpvId falseId = this->writeExpression(*t.ifFalse(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002427 this->writeInstruction(SpvOpSelect, this->getType(type), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002428 out);
2429 return result;
2430 }
Greg Daniel64773e62016-11-22 09:44:03 -05002431 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002432 // Adreno. Switched to storing the result in a temp variable as glslang does.
2433 SpvId var = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002434 this->writeInstruction(SpvOpVariable, this->getPointerType(type, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002435 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002436 SpvId trueLabel = this->nextId();
2437 SpvId falseLabel = this->nextId();
2438 SpvId end = this->nextId();
2439 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2440 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2441 this->writeLabel(trueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002442 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifTrue(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002443 this->writeInstruction(SpvOpBranch, end, out);
2444 this->writeLabel(falseLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002445 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifFalse(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002446 this->writeInstruction(SpvOpBranch, end, out);
2447 this->writeLabel(end, out);
2448 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002449 this->writeInstruction(SpvOpLoad, this->getType(type), result, var, out);
2450 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002451 return result;
2452}
2453
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002454SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002455 const Type& type = p.type();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002456 if (p.getOperator() == Token::Kind::TK_MINUS) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002457 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002458 SpvId typeId = this->getType(type);
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002459 SpvId expr = this->writeExpression(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002460 if (is_float(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002461 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002462 } else if (is_signed(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002463 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2464 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002465#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002466 ABORT("unsupported prefix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002467#endif
Brian Salomon23356442018-11-30 15:33:19 -05002468 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002469 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002470 return result;
2471 }
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002472 switch (p.getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002473 case Token::Kind::TK_PLUS:
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002474 return this->writeExpression(*p.operand(), out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002475 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002476 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002477 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
2478 SpvId result = this->writeBinaryOperation(type, type, lv->load(out), one,
Greg Daniel64773e62016-11-22 09:44:03 -05002479 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002480 out);
2481 lv->store(result, out);
2482 return result;
2483 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002484 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002485 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002486 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
2487 SpvId result = this->writeBinaryOperation(type, type, lv->load(out), one, SpvOpFSub,
2488 SpvOpISub, SpvOpISub, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002489 lv->store(result, out);
2490 return result;
2491 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002492 case Token::Kind::TK_LOGICALNOT: {
John Stiles4a7dc462020-11-25 11:08:08 -05002493 SkASSERT(p.operand()->type().isBoolean());
ethannicholasb3058bd2016-07-01 08:22:01 -07002494 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002495 this->writeInstruction(SpvOpLogicalNot, this->getType(type), result,
2496 this->writeExpression(*p.operand(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002497 return result;
2498 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002499 case Token::Kind::TK_BITWISENOT: {
ethannicholas5961bc92016-10-12 06:39:56 -07002500 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002501 this->writeInstruction(SpvOpNot, this->getType(type), result,
2502 this->writeExpression(*p.operand(), out), out);
ethannicholas5961bc92016-10-12 06:39:56 -07002503 return result;
2504 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002505 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002506#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002507 ABORT("unsupported prefix expression: %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002508#endif
2509 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002510 }
2511}
2512
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002513SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002514 const Type& type = p.type();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002515 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002516 SpvId result = lv->load(out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002517 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002518 switch (p.getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002519 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002520 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002521 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2522 lv->store(temp, out);
2523 return result;
2524 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002525 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002526 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002527 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2528 lv->store(temp, out);
2529 return result;
2530 }
2531 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002532#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002533 ABORT("unsupported postfix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002534#endif
2535 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002536 }
2537}
2538
ethannicholasf789b382016-08-03 12:43:36 -07002539SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
Ethan Nicholas59d660c2020-09-28 09:18:15 -04002540 if (b.value()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002541 if (fBoolTrue == 0) {
2542 fBoolTrue = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002543 this->writeInstruction(SpvOpConstantTrue, this->getType(b.type()), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002544 fConstantBuffer);
2545 }
2546 return fBoolTrue;
2547 } else {
2548 if (fBoolFalse == 0) {
2549 fBoolFalse = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002550 this->writeInstruction(SpvOpConstantFalse, this->getType(b.type()), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002551 fConstantBuffer);
2552 }
2553 return fBoolFalse;
2554 }
2555}
2556
ethannicholasf789b382016-08-03 12:43:36 -07002557SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002558 const Type& type = i.type();
2559 ConstantType constantType;
John Stilesfd41d872020-11-25 22:39:45 -05002560 if (type == *fContext.fInt_Type || type.typeKind() == Type::TypeKind::kEnum) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002561 constantType = ConstantType::kInt;
2562 } else if (type == *fContext.fUInt_Type) {
2563 constantType = ConstantType::kUInt;
2564 } else if (type == *fContext.fShort_Type || type == *fContext.fByte_Type) {
2565 constantType = ConstantType::kShort;
2566 } else if (type == *fContext.fUShort_Type || type == *fContext.fUByte_Type) {
2567 constantType = ConstantType::kUShort;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002568 } else {
2569 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002570 }
Ethan Nicholase96cdd12020-09-28 16:27:18 -04002571 std::pair<ConstantValue, ConstantType> key(i.value(), constantType);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002572 auto entry = fNumberConstants.find(key);
2573 if (entry == fNumberConstants.end()) {
2574 SpvId result = this->nextId();
Ethan Nicholase96cdd12020-09-28 16:27:18 -04002575 this->writeInstruction(SpvOpConstant, this->getType(type), result, (SpvId) i.value(),
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002576 fConstantBuffer);
2577 fNumberConstants[key] = result;
2578 return result;
2579 }
2580 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002581}
2582
ethannicholasf789b382016-08-03 12:43:36 -07002583SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002584 const Type& type = f.type();
2585 ConstantType constantType;
2586 if (type == *fContext.fHalf_Type) {
2587 constantType = ConstantType::kHalf;
ethannicholasb3058bd2016-07-01 08:22:01 -07002588 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002589 constantType = ConstantType::kFloat;
ethannicholasb3058bd2016-07-01 08:22:01 -07002590 }
Ethan Nicholasa3f22f12020-10-01 12:13:17 -04002591 float value = (float) f.value();
2592 std::pair<ConstantValue, ConstantType> key(f.value(), constantType);
John Stiles8c578662020-06-01 15:32:47 +00002593 auto entry = fNumberConstants.find(key);
2594 if (entry == fNumberConstants.end()) {
2595 SpvId result = this->nextId();
2596 uint32_t bits;
2597 SkASSERT(sizeof(bits) == sizeof(value));
2598 memcpy(&bits, &value, sizeof(bits));
Ethan Nicholas30d30222020-09-11 12:27:26 -04002599 this->writeInstruction(SpvOpConstant, this->getType(type), result, bits,
John Stiles8c578662020-06-01 15:32:47 +00002600 fConstantBuffer);
2601 fNumberConstants[key] = result;
2602 return result;
2603 }
2604 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002605}
2606
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002607SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002608 SpvId result = fFunctionMap[&f];
Ethan Nicholased84b732020-10-08 11:45:44 -04002609 this->writeInstruction(SpvOpFunction, this->getType(f.returnType()), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002610 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04002611 this->writeInstruction(SpvOpName, result, f.name(), fNameBuffer);
Brian Osman5bf3e202020-10-13 10:34:18 -04002612 const std::vector<const Variable*>& parameters = f.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -04002613 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002614 SpvId id = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -04002615 fVariableMap[parameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002616 SpvId type;
Ethan Nicholased84b732020-10-08 11:45:44 -04002617 type = this->getPointerType(parameters[i]->type(), SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002618 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2619 }
2620 return result;
2621}
2622
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002623SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2624 fVariableBuffer.reset();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002625 SpvId result = this->writeFunctionStart(f.declaration(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002626 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002627 StringStream bodyBuffer;
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002628 this->writeBlock((Block&) *f.body(), bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002629 write_stringstream(fVariableBuffer, out);
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002630 if (f.declaration().name() == "main") {
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002631 write_stringstream(fGlobalInitializersBuffer, out);
2632 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002633 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002634 if (fCurrentBlock) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002635 if (f.declaration().returnType() == *fContext.fVoid_Type) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002636 this->writeInstruction(SpvOpReturn, out);
2637 } else {
2638 this->writeInstruction(SpvOpUnreachable, out);
2639 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002640 }
2641 this->writeInstruction(SpvOpFunctionEnd, out);
2642 return result;
2643}
2644
2645void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2646 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002647 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002648 fDecorationBuffer);
2649 }
2650 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002651 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002652 fDecorationBuffer);
2653 }
2654 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002655 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002656 fDecorationBuffer);
2657 }
2658 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002659 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002660 fDecorationBuffer);
2661 }
Greg Daniel64773e62016-11-22 09:44:03 -05002662 if (layout.fInputAttachmentIndex >= 0) {
2663 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2664 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002665 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002666 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002667 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002668 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002669 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002670 fDecorationBuffer);
2671 }
2672}
2673
2674void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2675 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002676 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002677 layout.fLocation, fDecorationBuffer);
2678 }
2679 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002680 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002681 layout.fBinding, fDecorationBuffer);
2682 }
2683 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002684 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002685 layout.fIndex, fDecorationBuffer);
2686 }
2687 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002688 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002689 layout.fSet, fDecorationBuffer);
2690 }
Greg Daniel64773e62016-11-22 09:44:03 -05002691 if (layout.fInputAttachmentIndex >= 0) {
2692 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2693 layout.fInputAttachmentIndex, fDecorationBuffer);
2694 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002695 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002696 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002697 layout.fBuiltin, fDecorationBuffer);
2698 }
2699}
2700
Ethan Nicholas81d15112018-07-13 12:48:50 -04002701static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2702 switch (m.fLayout.fPrimitive) {
2703 case Layout::kPoints_Primitive:
2704 *outSkInCount = 1;
2705 break;
2706 case Layout::kLines_Primitive:
2707 *outSkInCount = 2;
2708 break;
2709 case Layout::kLinesAdjacency_Primitive:
2710 *outSkInCount = 4;
2711 break;
2712 case Layout::kTriangles_Primitive:
2713 *outSkInCount = 3;
2714 break;
2715 case Layout::kTrianglesAdjacency_Primitive:
2716 *outSkInCount = 6;
2717 break;
2718 default:
2719 return;
2720 }
2721}
2722
Stephen White88574972020-06-23 19:09:29 -04002723SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf, bool appendRTHeight) {
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002724 bool isBuffer = ((intf.variable().modifiers().fFlags & Modifiers::kBuffer_Flag) != 0);
2725 bool pushConstant = ((intf.variable().modifiers().fLayout.fFlags &
2726 Layout::kPushConstant_Flag) != 0);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002727 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2728 MemoryLayout(MemoryLayout::k430_Standard) :
2729 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002730 SpvId result = this->nextId();
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002731 const Type* type = &intf.variable().type();
John Stiles21f5f452020-11-30 09:57:59 -05002732 if (!MemoryLayout::LayoutIsSupported(*type)) {
John Stiles0023c0c2020-11-16 13:32:18 -05002733 fErrors.error(type->fOffset, "type '" + type->name() + "' is not permitted here");
2734 return this->nextId();
2735 }
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002736 Modifiers intfModifiers = intf.variable().modifiers();
2737 SpvStorageClass_ storageClass = get_storage_class(intfModifiers);
Stephen White88574972020-06-23 19:09:29 -04002738 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Greg Daniele6ab9982018-08-22 13:56:32 +00002739 SkASSERT(fRTHeightStructId == (SpvId) -1);
2740 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002741 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002742 fRTHeightStructId = result;
2743 fRTHeightFieldIndex = fields.size();
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002744 fRTHeightStorageClass = storageClass;
Greg Daniele6ab9982018-08-22 13:56:32 +00002745 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002746 type = new Type(type->fOffset, type->name(), fields);
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 }
Ethan Nicholase6592142020-09-08 10:22:09 -04002756 typeId = this->getType(Type("sk_in", Type::TypeKind::kArray,
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002757 intf.variable().type().componentType(),
Ethan Nicholase6592142020-09-08 10:22:09 -04002758 fSkInCount),
2759 memoryLayout);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002760 } else {
2761 typeId = this->getType(*type, memoryLayout);
2762 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002763 if (intfModifiers.fFlags & Modifiers::kBuffer_Flag) {
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002764 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002765 } else if (intfModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002766 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002767 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002768 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002769 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002770 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002771 Layout layout = intfModifiers.fLayout;
2772 if (intfModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002773 layout.fSet = 0;
2774 }
2775 this->writeLayout(layout, result);
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002776 fVariableMap[&intf.variable()] = result;
Stephen White88574972020-06-23 19:09:29 -04002777 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002778 delete type;
2779 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002780 return result;
2781}
2782
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002783void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002784 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2785}
2786
2787void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2788 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002789 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2790 }
2791}
2792
Brian Osman010ce6a2020-10-19 16:34:10 -04002793bool is_dead(const Variable& var, const ProgramUsage* usage) {
2794 ProgramUsage::VariableCounts counts = usage->get(var);
2795 if (counts.fRead || counts.fWrite) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002796 return false;
2797 }
2798 // not entirely sure what the rules are for when it's safe to elide interface variables, but it
2799 // causes various problems to elide some of them even when dead. But it also causes problems
2800 // *not* to elide sk_SampleMask when it's not being used.
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002801 if (!(var.modifiers().fFlags & (Modifiers::kIn_Flag |
2802 Modifiers::kOut_Flag |
2803 Modifiers::kUniform_Flag |
2804 Modifiers::kBuffer_Flag))) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002805 return true;
2806 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002807 return var.modifiers().fLayout.fBuiltin == SK_SAMPLEMASK_BUILTIN;
Chris Dalton2284aab2019-11-15 11:02:24 -07002808}
2809
ethannicholas5961bc92016-10-12 06:39:56 -07002810#define BUILTIN_IGNORE 9999
Brian Osmanc0213602020-10-06 14:43:32 -04002811void SPIRVCodeGenerator::writeGlobalVar(Program::Kind kind, const VarDeclaration& varDecl,
2812 OutputStream& out) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002813 const Variable& var = varDecl.var();
Brian Osmanc0213602020-10-06 14:43:32 -04002814 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2815 // in the OpenGL backend.
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002816 SkASSERT(!(var.modifiers().fFlags & (Modifiers::kReadOnly_Flag |
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002817 Modifiers::kWriteOnly_Flag |
2818 Modifiers::kCoherent_Flag |
2819 Modifiers::kVolatile_Flag |
2820 Modifiers::kRestrict_Flag)));
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002821 if (var.modifiers().fLayout.fBuiltin == BUILTIN_IGNORE) {
Brian Osmanc0213602020-10-06 14:43:32 -04002822 return;
2823 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002824 if (var.modifiers().fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
Brian Osmanc0213602020-10-06 14:43:32 -04002825 kind != Program::kFragment_Kind) {
2826 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
2827 return;
2828 }
Brian Osman010ce6a2020-10-19 16:34:10 -04002829 if (is_dead(var, fProgram.fUsage.get())) {
Brian Osmanc0213602020-10-06 14:43:32 -04002830 return;
2831 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002832 const Type& type = var.type();
Brian Osmanc0213602020-10-06 14:43:32 -04002833 SpvStorageClass_ storageClass;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002834 if (var.modifiers().fFlags & Modifiers::kIn_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002835 storageClass = SpvStorageClassInput;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002836 } else if (var.modifiers().fFlags & Modifiers::kOut_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002837 storageClass = SpvStorageClassOutput;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002838 } else if (var.modifiers().fFlags & Modifiers::kUniform_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002839 if (type.typeKind() == Type::TypeKind::kSampler ||
2840 type.typeKind() == Type::TypeKind::kSeparateSampler ||
2841 type.typeKind() == Type::TypeKind::kTexture) {
2842 storageClass = SpvStorageClassUniformConstant;
ethannicholasb3058bd2016-07-01 08:22:01 -07002843 } else {
Brian Osmanc0213602020-10-06 14:43:32 -04002844 storageClass = SpvStorageClassUniform;
ethannicholasb3058bd2016-07-01 08:22:01 -07002845 }
Brian Osmanc0213602020-10-06 14:43:32 -04002846 } else {
2847 storageClass = SpvStorageClassPrivate;
2848 }
2849 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002850 fVariableMap[&var] = id;
Brian Osmanc0213602020-10-06 14:43:32 -04002851 SpvId typeId;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002852 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osmanc0213602020-10-06 14:43:32 -04002853 typeId = this->getPointerType(
2854 Type("sk_in", Type::TypeKind::kArray, type.componentType(), fSkInCount),
2855 storageClass);
2856 } else {
2857 typeId = this->getPointerType(type, storageClass);
2858 }
2859 this->writeInstruction(SpvOpVariable, typeId, id, storageClass, fConstantBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002860 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002861 this->writePrecisionModifier(type, id);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002862 if (varDecl.value()) {
Brian Osmanc0213602020-10-06 14:43:32 -04002863 SkASSERT(!fCurrentBlock);
2864 fCurrentBlock = -1;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002865 SpvId value = this->writeExpression(*varDecl.value(), fGlobalInitializersBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002866 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
2867 fCurrentBlock = 0;
2868 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002869 this->writeLayout(var.modifiers().fLayout, id);
2870 if (var.modifiers().fFlags & Modifiers::kFlat_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002871 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2872 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002873 if (var.modifiers().fFlags & Modifiers::kNoPerspective_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002874 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2875 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002876 }
2877}
2878
Brian Osmanc0213602020-10-06 14:43:32 -04002879void SPIRVCodeGenerator::writeVarDeclaration(const VarDeclaration& varDecl, OutputStream& out) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002880 const Variable& var = varDecl.var();
Brian Osmanc0213602020-10-06 14:43:32 -04002881 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2882 // in the OpenGL backend.
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002883 SkASSERT(!(var.modifiers().fFlags & (Modifiers::kReadOnly_Flag |
2884 Modifiers::kWriteOnly_Flag |
2885 Modifiers::kCoherent_Flag |
2886 Modifiers::kVolatile_Flag |
2887 Modifiers::kRestrict_Flag)));
Brian Osmanc0213602020-10-06 14:43:32 -04002888 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002889 fVariableMap[&var] = id;
2890 SpvId type = this->getPointerType(var.type(), SpvStorageClassFunction);
Brian Osmanc0213602020-10-06 14:43:32 -04002891 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002892 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
2893 if (varDecl.value()) {
2894 SpvId value = this->writeExpression(*varDecl.value(), out);
Brian Osmanc0213602020-10-06 14:43:32 -04002895 this->writeInstruction(SpvOpStore, id, value, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002896 }
2897}
2898
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002899void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002900 switch (s.kind()) {
John Stiles98c1f822020-09-09 14:18:53 -04002901 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04002902 case Statement::Kind::kNop:
Ethan Nicholascb670962017-04-20 19:31:52 -04002903 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002904 case Statement::Kind::kBlock:
ethannicholasb3058bd2016-07-01 08:22:01 -07002905 this->writeBlock((Block&) s, out);
2906 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002907 case Statement::Kind::kExpression:
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04002908 this->writeExpression(*s.as<ExpressionStatement>().expression(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002909 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002910 case Statement::Kind::kReturn:
John Stiles26f98502020-08-18 09:30:51 -04002911 this->writeReturnStatement(s.as<ReturnStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002912 break;
Brian Osmanc0213602020-10-06 14:43:32 -04002913 case Statement::Kind::kVarDeclaration:
2914 this->writeVarDeclaration(s.as<VarDeclaration>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002915 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002916 case Statement::Kind::kIf:
John Stiles26f98502020-08-18 09:30:51 -04002917 this->writeIfStatement(s.as<IfStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002918 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002919 case Statement::Kind::kFor:
John Stiles26f98502020-08-18 09:30:51 -04002920 this->writeForStatement(s.as<ForStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002921 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002922 case Statement::Kind::kWhile:
John Stiles26f98502020-08-18 09:30:51 -04002923 this->writeWhileStatement(s.as<WhileStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002924 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002925 case Statement::Kind::kDo:
John Stiles26f98502020-08-18 09:30:51 -04002926 this->writeDoStatement(s.as<DoStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002927 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002928 case Statement::Kind::kSwitch:
John Stiles26f98502020-08-18 09:30:51 -04002929 this->writeSwitchStatement(s.as<SwitchStatement>(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002930 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002931 case Statement::Kind::kBreak:
ethannicholasb3058bd2016-07-01 08:22:01 -07002932 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2933 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002934 case Statement::Kind::kContinue:
ethannicholasb3058bd2016-07-01 08:22:01 -07002935 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2936 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002937 case Statement::Kind::kDiscard:
ethannicholasb3058bd2016-07-01 08:22:01 -07002938 this->writeInstruction(SpvOpKill, out);
2939 break;
2940 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002941#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002942 ABORT("unsupported statement: %s", s.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002943#endif
2944 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002945 }
2946}
2947
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002948void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04002949 for (const std::unique_ptr<Statement>& stmt : b.children()) {
2950 this->writeStatement(*stmt, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002951 }
2952}
2953
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002954void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002955 SpvId test = this->writeExpression(*stmt.test(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002956 SpvId ifTrue = this->nextId();
2957 SpvId ifFalse = this->nextId();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002958 if (stmt.ifFalse()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002959 SpvId end = this->nextId();
2960 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2961 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2962 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002963 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002964 if (fCurrentBlock) {
2965 this->writeInstruction(SpvOpBranch, end, out);
2966 }
2967 this->writeLabel(ifFalse, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002968 this->writeStatement(*stmt.ifFalse(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002969 if (fCurrentBlock) {
2970 this->writeInstruction(SpvOpBranch, end, out);
2971 }
2972 this->writeLabel(end, out);
2973 } else {
2974 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2975 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2976 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002977 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002978 if (fCurrentBlock) {
2979 this->writeInstruction(SpvOpBranch, ifFalse, out);
2980 }
2981 this->writeLabel(ifFalse, out);
2982 }
2983}
2984
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002985void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04002986 if (f.initializer()) {
2987 this->writeStatement(*f.initializer(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002988 }
2989 SpvId header = this->nextId();
2990 SpvId start = this->nextId();
2991 SpvId body = this->nextId();
2992 SpvId next = this->nextId();
2993 fContinueTarget.push(next);
2994 SpvId end = this->nextId();
2995 fBreakTarget.push(end);
2996 this->writeInstruction(SpvOpBranch, header, out);
2997 this->writeLabel(header, out);
2998 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002999 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003000 this->writeLabel(start, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003001 if (f.test()) {
3002 SpvId test = this->writeExpression(*f.test(), out);
ethannicholas22f939e2016-10-13 13:25:34 -07003003 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
3004 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003005 this->writeLabel(body, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003006 this->writeStatement(*f.statement(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003007 if (fCurrentBlock) {
3008 this->writeInstruction(SpvOpBranch, next, out);
3009 }
3010 this->writeLabel(next, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003011 if (f.next()) {
3012 this->writeExpression(*f.next(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003013 }
3014 this->writeInstruction(SpvOpBranch, header, out);
3015 this->writeLabel(end, out);
3016 fBreakTarget.pop();
3017 fContinueTarget.pop();
3018}
3019
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003020void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003021 SpvId header = this->nextId();
3022 SpvId start = this->nextId();
3023 SpvId body = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003024 SpvId continueTarget = this->nextId();
3025 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003026 SpvId end = this->nextId();
3027 fBreakTarget.push(end);
3028 this->writeInstruction(SpvOpBranch, header, out);
3029 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003030 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003031 this->writeInstruction(SpvOpBranch, start, out);
3032 this->writeLabel(start, out);
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003033 SpvId test = this->writeExpression(*w.test(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003034 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
3035 this->writeLabel(body, out);
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003036 this->writeStatement(*w.statement(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003037 if (fCurrentBlock) {
Ethan Nicholas0d997662019-04-08 09:46:01 -04003038 this->writeInstruction(SpvOpBranch, continueTarget, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003039 }
Ethan Nicholas0d997662019-04-08 09:46:01 -04003040 this->writeLabel(continueTarget, out);
3041 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003042 this->writeLabel(end, out);
3043 fBreakTarget.pop();
3044 fContinueTarget.pop();
3045}
3046
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003047void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003048 SpvId header = this->nextId();
3049 SpvId start = this->nextId();
3050 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003051 SpvId continueTarget = this->nextId();
3052 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003053 SpvId end = this->nextId();
3054 fBreakTarget.push(end);
3055 this->writeInstruction(SpvOpBranch, header, out);
3056 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003057 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003058 this->writeInstruction(SpvOpBranch, start, out);
3059 this->writeLabel(start, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003060 this->writeStatement(*d.statement(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003061 if (fCurrentBlock) {
3062 this->writeInstruction(SpvOpBranch, next, out);
3063 }
3064 this->writeLabel(next, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003065 SpvId test = this->writeExpression(*d.test(), out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003066 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
3067 this->writeLabel(continueTarget, out);
3068 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003069 this->writeLabel(end, out);
3070 fBreakTarget.pop();
3071 fContinueTarget.pop();
3072}
3073
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003074void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04003075 SpvId value = this->writeExpression(*s.value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003076 std::vector<SpvId> labels;
3077 SpvId end = this->nextId();
3078 SpvId defaultLabel = end;
3079 fBreakTarget.push(end);
3080 int size = 3;
John Stiles2d4f9592020-10-30 10:29:12 -04003081 auto& cases = s.cases();
3082 for (const std::unique_ptr<SwitchCase>& c : cases) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003083 SpvId label = this->nextId();
3084 labels.push_back(label);
John Stiles2d4f9592020-10-30 10:29:12 -04003085 if (c->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003086 size += 2;
3087 } else {
3088 defaultLabel = label;
3089 }
3090 }
3091 labels.push_back(end);
3092 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3093 this->writeOpCode(SpvOpSwitch, size, out);
3094 this->writeWord(value, out);
3095 this->writeWord(defaultLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04003096 for (size_t i = 0; i < cases.size(); ++i) {
3097 if (!cases[i]->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003098 continue;
3099 }
John Stiles2d4f9592020-10-30 10:29:12 -04003100 this->writeWord(cases[i]->value()->as<IntLiteral>().value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003101 this->writeWord(labels[i], out);
3102 }
John Stiles2d4f9592020-10-30 10:29:12 -04003103 for (size_t i = 0; i < cases.size(); ++i) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003104 this->writeLabel(labels[i], out);
John Stiles2d4f9592020-10-30 10:29:12 -04003105 for (const auto& stmt : cases[i]->statements()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003106 this->writeStatement(*stmt, out);
3107 }
3108 if (fCurrentBlock) {
3109 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3110 }
3111 }
3112 this->writeLabel(end, out);
3113 fBreakTarget.pop();
3114}
3115
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003116void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003117 if (r.expression()) {
3118 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.expression(), out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003119 out);
3120 } else {
3121 this->writeInstruction(SpvOpReturn, out);
3122 }
3123}
3124
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003125void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003126 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003127 int invocations = 1;
Brian Osman133724c2020-10-28 14:14:39 -04003128 for (const ProgramElement* e : fProgram.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003129 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04003130 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003131 if (m.fFlags & Modifiers::kIn_Flag) {
3132 if (m.fLayout.fInvocations != -1) {
3133 invocations = m.fLayout.fInvocations;
3134 }
3135 SpvId input;
3136 switch (m.fLayout.fPrimitive) {
3137 case Layout::kPoints_Primitive:
3138 input = SpvExecutionModeInputPoints;
3139 break;
3140 case Layout::kLines_Primitive:
3141 input = SpvExecutionModeInputLines;
3142 break;
3143 case Layout::kLinesAdjacency_Primitive:
3144 input = SpvExecutionModeInputLinesAdjacency;
3145 break;
3146 case Layout::kTriangles_Primitive:
3147 input = SpvExecutionModeTriangles;
3148 break;
3149 case Layout::kTrianglesAdjacency_Primitive:
3150 input = SpvExecutionModeInputTrianglesAdjacency;
3151 break;
3152 default:
3153 input = 0;
3154 break;
3155 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003156 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003157 if (input) {
3158 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3159 }
3160 } else if (m.fFlags & Modifiers::kOut_Flag) {
3161 SpvId output;
3162 switch (m.fLayout.fPrimitive) {
3163 case Layout::kPoints_Primitive:
3164 output = SpvExecutionModeOutputPoints;
3165 break;
3166 case Layout::kLineStrip_Primitive:
3167 output = SpvExecutionModeOutputLineStrip;
3168 break;
3169 case Layout::kTriangleStrip_Primitive:
3170 output = SpvExecutionModeOutputTriangleStrip;
3171 break;
3172 default:
3173 output = 0;
3174 break;
3175 }
3176 if (output) {
3177 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3178 }
3179 if (m.fLayout.fMaxVertices != -1) {
3180 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3181 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3182 out);
3183 }
3184 }
3185 }
3186 }
3187 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3188 invocations, out);
3189}
3190
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003191void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003192 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003193 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003194 std::set<SpvId> interfaceVars;
Brian Osman1f8f5752020-10-28 14:46:21 -04003195 // assign IDs to functions
Brian Osman133724c2020-10-28 14:14:39 -04003196 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003197 switch (e->kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04003198 case ProgramElement::Kind::kFunction: {
Brian Osman1179fcf2020-10-08 16:04:40 -04003199 const FunctionDefinition& f = e->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04003200 fFunctionMap[&f.declaration()] = this->nextId();
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003201 break;
3202 }
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003203 default:
3204 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003205 }
3206 }
Brian Osman133724c2020-10-28 14:14:39 -04003207 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003208 if (e->is<InterfaceBlock>()) {
Brian Osman1f8f5752020-10-28 14:46:21 -04003209 const InterfaceBlock& intf = e->as<InterfaceBlock>();
ethannicholasb3058bd2016-07-01 08:22:01 -07003210 SpvId id = this->writeInterfaceBlock(intf);
Brian Osman1f8f5752020-10-28 14:46:21 -04003211
3212 const Modifiers& modifiers = intf.variable().modifiers();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003213 if (((modifiers.fFlags & Modifiers::kIn_Flag) ||
3214 (modifiers.fFlags & Modifiers::kOut_Flag)) &&
3215 modifiers.fLayout.fBuiltin == -1 &&
Brian Osman010ce6a2020-10-19 16:34:10 -04003216 !is_dead(intf.variable(), fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003217 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003218 }
3219 }
3220 }
Brian Osman133724c2020-10-28 14:14:39 -04003221 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003222 if (e->is<GlobalVarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04003223 this->writeGlobalVar(program.fKind,
3224 e->as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>(),
3225 body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003226 }
3227 }
Brian Osman133724c2020-10-28 14:14:39 -04003228 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003229 if (e->is<FunctionDefinition>()) {
3230 this->writeFunction(e->as<FunctionDefinition>(), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003231 }
3232 }
ethannicholasd598f792016-07-25 10:08:54 -07003233 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003234 for (auto entry : fFunctionMap) {
Ethan Nicholase2c49992020-10-05 11:49:11 -04003235 if (entry.first->name() == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003236 main = entry.first;
3237 }
3238 }
Ethan Nicholas1a668d22019-04-18 10:37:40 -04003239 if (!main) {
3240 fErrors.error(0, "program does not contain a main() function");
3241 return;
3242 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003243 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003244 const Variable* var = entry.first;
Ethan Nicholas453f67f2020-10-09 10:43:45 -04003245 if (var->storage() == Variable::Storage::kGlobal &&
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003246 ((var->modifiers().fFlags & Modifiers::kIn_Flag) ||
Brian Osman010ce6a2020-10-19 16:34:10 -04003247 (var->modifiers().fFlags & Modifiers::kOut_Flag)) &&
3248 !is_dead(*var, fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003249 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003250 }
3251 }
3252 this->writeCapabilities(out);
3253 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3254 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003255 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->name().fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003256 (int32_t) interfaceVars.size(), out);
3257 switch (program.fKind) {
3258 case Program::kVertex_Kind:
3259 this->writeWord(SpvExecutionModelVertex, out);
3260 break;
3261 case Program::kFragment_Kind:
3262 this->writeWord(SpvExecutionModelFragment, out);
3263 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003264 case Program::kGeometry_Kind:
3265 this->writeWord(SpvExecutionModelGeometry, out);
3266 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003267 default:
3268 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003269 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003270 SpvId entryPoint = fFunctionMap[main];
3271 this->writeWord(entryPoint, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003272 this->writeString(main->name().fChars, main->name().fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003273 for (int var : interfaceVars) {
3274 this->writeWord(var, out);
3275 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003276 if (program.fKind == Program::kGeometry_Kind) {
3277 this->writeGeometryShaderExecutionMode(entryPoint, out);
3278 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003279 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003280 this->writeInstruction(SpvOpExecutionMode,
3281 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003282 SpvExecutionModeOriginUpperLeft,
3283 out);
3284 }
Brian Osman133724c2020-10-28 14:14:39 -04003285 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003286 if (e->is<Extension>()) {
3287 this->writeInstruction(SpvOpSourceExtension, e->as<Extension>().name().c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003288 }
3289 }
Greg Daniel64773e62016-11-22 09:44:03 -05003290
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003291 write_stringstream(fExtraGlobalsBuffer, out);
3292 write_stringstream(fNameBuffer, out);
3293 write_stringstream(fDecorationBuffer, out);
3294 write_stringstream(fConstantBuffer, out);
3295 write_stringstream(fExternalFunctionsBuffer, out);
3296 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003297}
3298
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003299bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003300 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003301 this->writeWord(SpvMagicNumber, *fOut);
3302 this->writeWord(SpvVersion, *fOut);
3303 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003304 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003305 this->writeInstructions(fProgram, buffer);
3306 this->writeWord(fIdCount, *fOut);
3307 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003308 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003309 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003310}
3311
John Stilesa6841be2020-08-06 14:11:56 -04003312} // namespace SkSL