blob: c63d84d36be288174910d0567fefcf24b2128c18 [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);
John Stiles01957272020-12-09 17:14:47 -050075 fIntrinsicMap[String("modf")] = ALL_GLSL(Modf);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050076 fIntrinsicMap[String("min")] = SPECIAL(Min);
77 fIntrinsicMap[String("max")] = SPECIAL(Max);
78 fIntrinsicMap[String("clamp")] = SPECIAL(Clamp);
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040079 fIntrinsicMap[String("saturate")] = SPECIAL(Saturate);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040080 fIntrinsicMap[String("dot")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
Ethan Nicholas0187ae62017-05-03 11:03:44 -040081 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050082 fIntrinsicMap[String("mix")] = SPECIAL(Mix);
Brian Osman6ba3be12020-11-13 16:32:52 -050083 fIntrinsicMap[String("step")] = SPECIAL(Step);
84 fIntrinsicMap[String("smoothstep")] = SPECIAL(SmoothStep);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040085 fIntrinsicMap[String("fma")] = ALL_GLSL(Fma);
86 fIntrinsicMap[String("frexp")] = ALL_GLSL(Frexp);
87 fIntrinsicMap[String("ldexp")] = ALL_GLSL(Ldexp);
ethannicholasb3058bd2016-07-01 08:22:01 -070088
Ethan Nicholas0df1b042017-03-31 13:56:23 -040089#define PACK(type) fIntrinsicMap[String("pack" #type)] = ALL_GLSL(Pack ## type); \
90 fIntrinsicMap[String("unpack" #type)] = ALL_GLSL(Unpack ## type)
ethannicholasb3058bd2016-07-01 08:22:01 -070091 PACK(Snorm4x8);
92 PACK(Unorm4x8);
93 PACK(Snorm2x16);
94 PACK(Unorm2x16);
95 PACK(Half2x16);
96 PACK(Double2x32);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040097 fIntrinsicMap[String("length")] = ALL_GLSL(Length);
98 fIntrinsicMap[String("distance")] = ALL_GLSL(Distance);
99 fIntrinsicMap[String("cross")] = ALL_GLSL(Cross);
100 fIntrinsicMap[String("normalize")] = ALL_GLSL(Normalize);
John Stiles0d19fb42020-12-10 17:04:37 -0500101 fIntrinsicMap[String("faceforward")] = ALL_GLSL(FaceForward);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400102 fIntrinsicMap[String("reflect")] = ALL_GLSL(Reflect);
103 fIntrinsicMap[String("refract")] = ALL_GLSL(Refract);
104 fIntrinsicMap[String("findLSB")] = ALL_GLSL(FindILsb);
105 fIntrinsicMap[String("findMSB")] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
106 fIntrinsicMap[String("dFdx")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400107 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700108 fIntrinsicMap[String("dFdy")] = SPECIAL(DFdy);
Chris Dalton09212192018-11-13 15:07:24 -0500109 fIntrinsicMap[String("fwidth")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFwidth,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400110 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400111 fIntrinsicMap[String("makeSampler2D")] = SPECIAL(SampledImage);
112
Ethan Nicholas13863662019-07-29 13:05:15 -0400113 fIntrinsicMap[String("sample")] = SPECIAL(Texture);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400114 fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
Greg Daniel64773e62016-11-22 09:44:03 -0500115
John Stilescc9ff002020-12-09 18:39:41 -0500116 fIntrinsicMap[String("floatBitsToInt")] = ALL_SPIRV(Bitcast);
117 fIntrinsicMap[String("floatBitsToUint")] = ALL_SPIRV(Bitcast);
118 fIntrinsicMap[String("intBitsToFloat")] = ALL_SPIRV(Bitcast);
119 fIntrinsicMap[String("uintBitsToFloat")] = ALL_SPIRV(Bitcast);
120
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400121 fIntrinsicMap[String("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400122 SpvOpUndef, SpvOpUndef, SpvOpAny);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400123 fIntrinsicMap[String("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400124 SpvOpUndef, SpvOpUndef, SpvOpAll);
Brian Osman540c13a2020-11-24 16:55:34 -0500125 fIntrinsicMap[String("not")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
126 SpvOpUndef, SpvOpUndef,
127 SpvOpLogicalNot);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400128 fIntrinsicMap[String("equal")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400129 SpvOpFOrdEqual, SpvOpIEqual,
130 SpvOpIEqual, SpvOpLogicalEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400131 fIntrinsicMap[String("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400132 SpvOpFOrdNotEqual, SpvOpINotEqual,
133 SpvOpINotEqual,
134 SpvOpLogicalNotEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400135 fIntrinsicMap[String("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500136 SpvOpFOrdLessThan, SpvOpSLessThan,
137 SpvOpULessThan, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400138 fIntrinsicMap[String("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500139 SpvOpFOrdLessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400140 SpvOpSLessThanEqual,
141 SpvOpULessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400142 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400143 fIntrinsicMap[String("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500144 SpvOpFOrdGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400145 SpvOpSGreaterThan,
146 SpvOpUGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400147 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400148 fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500149 SpvOpFOrdGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400150 SpvOpSGreaterThanEqual,
151 SpvOpUGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400152 SpvOpUndef);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400153 fIntrinsicMap[String("EmitVertex")] = ALL_SPIRV(EmitVertex);
154 fIntrinsicMap[String("EndPrimitive")] = ALL_SPIRV(EndPrimitive);
ethannicholasb3058bd2016-07-01 08:22:01 -0700155// interpolateAt* not yet supported...
156}
157
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400158void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700159 out.write((const char*) &word, sizeof(word));
ethannicholasb3058bd2016-07-01 08:22:01 -0700160}
161
ethannicholasd598f792016-07-25 10:08:54 -0700162static bool is_float(const Context& context, const Type& type) {
Ethan Nicholas0df21132018-07-10 09:37:51 -0400163 if (type.columns() > 1) {
ethannicholasd598f792016-07-25 10:08:54 -0700164 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700165 }
John Stiles123501f2020-12-09 10:08:13 -0500166 return type.isFloat();
ethannicholasb3058bd2016-07-01 08:22:01 -0700167}
168
ethannicholasd598f792016-07-25 10:08:54 -0700169static bool is_signed(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500170 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700171 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700172 }
John Stiles123501f2020-12-09 10:08:13 -0500173 return type.isSigned();
ethannicholasb3058bd2016-07-01 08:22:01 -0700174}
175
ethannicholasd598f792016-07-25 10:08:54 -0700176static bool is_unsigned(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500177 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700178 return is_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700179 }
John Stiles123501f2020-12-09 10:08:13 -0500180 return type.isUnsigned();
ethannicholasb3058bd2016-07-01 08:22:01 -0700181}
182
ethannicholasd598f792016-07-25 10:08:54 -0700183static bool is_bool(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500184 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700185 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700186 }
John Stiles123501f2020-12-09 10:08:13 -0500187 return type.isBoolean();
ethannicholasb3058bd2016-07-01 08:22:01 -0700188}
189
ethannicholasd598f792016-07-25 10:08:54 -0700190static bool is_out(const Variable& var) {
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400191 return (var.modifiers().fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700192}
193
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400194void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400195 SkASSERT(opCode != SpvOpLoad || &out != &fConstantBuffer);
196 SkASSERT(opCode != SpvOpUndef);
ethannicholasb3058bd2016-07-01 08:22:01 -0700197 switch (opCode) {
198 case SpvOpReturn: // fall through
199 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700200 case SpvOpKill: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700201 case SpvOpBranch: // fall through
202 case SpvOpBranchConditional:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400203 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700204 fCurrentBlock = 0;
205 break;
206 case SpvOpConstant: // fall through
207 case SpvOpConstantTrue: // fall through
208 case SpvOpConstantFalse: // fall through
209 case SpvOpConstantComposite: // fall through
210 case SpvOpTypeVoid: // fall through
211 case SpvOpTypeInt: // fall through
212 case SpvOpTypeFloat: // fall through
213 case SpvOpTypeBool: // fall through
214 case SpvOpTypeVector: // fall through
215 case SpvOpTypeMatrix: // fall through
216 case SpvOpTypeArray: // fall through
217 case SpvOpTypePointer: // fall through
218 case SpvOpTypeFunction: // fall through
219 case SpvOpTypeRuntimeArray: // fall through
220 case SpvOpTypeStruct: // fall through
221 case SpvOpTypeImage: // fall through
222 case SpvOpTypeSampledImage: // fall through
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400223 case SpvOpTypeSampler: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700224 case SpvOpVariable: // fall through
225 case SpvOpFunction: // fall through
226 case SpvOpFunctionParameter: // fall through
227 case SpvOpFunctionEnd: // fall through
228 case SpvOpExecutionMode: // fall through
229 case SpvOpMemoryModel: // fall through
230 case SpvOpCapability: // fall through
231 case SpvOpExtInstImport: // fall through
232 case SpvOpEntryPoint: // fall through
233 case SpvOpSource: // fall through
234 case SpvOpSourceExtension: // fall through
235 case SpvOpName: // fall through
236 case SpvOpMemberName: // fall through
237 case SpvOpDecorate: // fall through
238 case SpvOpMemberDecorate:
239 break;
240 default:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400241 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700242 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700243 this->writeWord((length << 16) | opCode, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700244}
245
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400246void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700247 fCurrentBlock = label;
248 this->writeInstruction(SpvOpLabel, label, out);
249}
250
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400251void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700252 this->writeOpCode(opCode, 1, out);
253}
254
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400255void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700256 this->writeOpCode(opCode, 2, out);
257 this->writeWord(word1, out);
258}
259
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700260void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputStream& out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400261 out.write(string, length);
ethannicholasb3058bd2016-07-01 08:22:01 -0700262 switch (length % 4) {
263 case 1:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500264 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400265 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700266 case 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500267 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400268 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700269 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500270 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700271 break;
272 default:
273 this->writeWord(0, out);
274 }
275}
276
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700277void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out) {
278 this->writeOpCode(opCode, 1 + (string.fLength + 4) / 4, out);
279 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700280}
281
282
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700283void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400284 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700285 this->writeOpCode(opCode, 2 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700286 this->writeWord(word1, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700287 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700288}
289
Greg Daniel64773e62016-11-22 09:44:03 -0500290void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700291 StringFragment string, OutputStream& out) {
292 this->writeOpCode(opCode, 3 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700293 this->writeWord(word1, out);
294 this->writeWord(word2, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700295 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700296}
297
Greg Daniel64773e62016-11-22 09:44:03 -0500298void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400299 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700300 this->writeOpCode(opCode, 3, out);
301 this->writeWord(word1, out);
302 this->writeWord(word2, out);
303}
304
Greg Daniel64773e62016-11-22 09:44:03 -0500305void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400306 int32_t word3, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700307 this->writeOpCode(opCode, 4, out);
308 this->writeWord(word1, out);
309 this->writeWord(word2, out);
310 this->writeWord(word3, out);
311}
312
Greg Daniel64773e62016-11-22 09:44:03 -0500313void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400314 int32_t word3, int32_t word4, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700315 this->writeOpCode(opCode, 5, out);
316 this->writeWord(word1, out);
317 this->writeWord(word2, out);
318 this->writeWord(word3, out);
319 this->writeWord(word4, out);
320}
321
Greg Daniel64773e62016-11-22 09:44:03 -0500322void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
323 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400324 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700325 this->writeOpCode(opCode, 6, out);
326 this->writeWord(word1, out);
327 this->writeWord(word2, out);
328 this->writeWord(word3, out);
329 this->writeWord(word4, out);
330 this->writeWord(word5, out);
331}
332
Greg Daniel64773e62016-11-22 09:44:03 -0500333void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700334 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400335 int32_t word6, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700336 this->writeOpCode(opCode, 7, out);
337 this->writeWord(word1, out);
338 this->writeWord(word2, out);
339 this->writeWord(word3, out);
340 this->writeWord(word4, out);
341 this->writeWord(word5, out);
342 this->writeWord(word6, out);
343}
344
Greg Daniel64773e62016-11-22 09:44:03 -0500345void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700346 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400347 int32_t word6, int32_t word7, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700348 this->writeOpCode(opCode, 8, out);
349 this->writeWord(word1, out);
350 this->writeWord(word2, out);
351 this->writeWord(word3, out);
352 this->writeWord(word4, out);
353 this->writeWord(word5, out);
354 this->writeWord(word6, out);
355 this->writeWord(word7, out);
356}
357
Greg Daniel64773e62016-11-22 09:44:03 -0500358void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700359 int32_t word3, int32_t word4, int32_t word5,
360 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400361 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700362 this->writeOpCode(opCode, 9, out);
363 this->writeWord(word1, out);
364 this->writeWord(word2, out);
365 this->writeWord(word3, out);
366 this->writeWord(word4, out);
367 this->writeWord(word5, out);
368 this->writeWord(word6, out);
369 this->writeWord(word7, out);
370 this->writeWord(word8, out);
371}
372
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400373void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700374 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
375 if (fCapabilities & bit) {
376 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
377 }
378 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400379 if (fProgram.fKind == Program::kGeometry_Kind) {
380 this->writeInstruction(SpvOpCapability, SpvCapabilityGeometry, out);
381 }
Ethan Nicholas81d15112018-07-13 12:48:50 -0400382 else {
383 this->writeInstruction(SpvOpCapability, SpvCapabilityShader, out);
384 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700385}
386
387SpvId SPIRVCodeGenerator::nextId() {
388 return fIdCount++;
389}
390
Ethan Nicholas19671772016-11-28 16:30:17 -0500391void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
392 SpvId resultId) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400393 this->writeInstruction(SpvOpName, resultId, String(type.name()).c_str(), fNameBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700394 // go ahead and write all of the field types, so we don't inadvertently write them while we're
395 // in the middle of writing the struct instruction
396 std::vector<SpvId> types;
397 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500398 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700399 }
400 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
401 this->writeWord(resultId, fConstantBuffer);
402 for (SpvId id : types) {
403 this->writeWord(id, fConstantBuffer);
404 }
405 size_t offset = 0;
406 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400407 const Type::Field& field = type.fields()[i];
John Stiles21f5f452020-11-30 09:57:59 -0500408 if (!MemoryLayout::LayoutIsSupported(*field.fType)) {
John Stiles0023c0c2020-11-16 13:32:18 -0500409 fErrors.error(type.fOffset, "type '" + field.fType->name() + "' is not permitted here");
410 return;
411 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400412 size_t size = memoryLayout.size(*field.fType);
413 size_t alignment = memoryLayout.alignment(*field.fType);
414 const Layout& fieldLayout = field.fModifiers.fLayout;
Ethan Nicholas19671772016-11-28 16:30:17 -0500415 if (fieldLayout.fOffset >= 0) {
Greg Danieldbd44c72017-01-24 15:12:12 -0500416 if (fieldLayout.fOffset < (int) offset) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700417 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400418 "offset of field '" + field.fName + "' must be at "
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500419 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -0500420 }
421 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700422 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400423 "offset of field '" + field.fName + "' must be a multiple"
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500424 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -0500425 }
426 offset = fieldLayout.fOffset;
427 } else {
428 size_t mod = offset % alignment;
429 if (mod) {
430 offset += alignment - mod;
431 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700432 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400433 this->writeInstruction(SpvOpMemberName, resultId, i, field.fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500434 this->writeLayout(fieldLayout, resultId, i);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400435 if (field.fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -0500436 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700437 (SpvId) offset, fDecorationBuffer);
438 }
John Stiles9aeed132020-11-24 17:36:06 -0500439 if (field.fType->isMatrix()) {
Greg Daniel64773e62016-11-22 09:44:03 -0500440 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -0700441 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500442 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400443 (SpvId) memoryLayout.stride(*field.fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800444 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700445 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400446 if (!field.fType->highPrecision()) {
447 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i,
448 SpvDecorationRelaxedPrecision, fDecorationBuffer);
449 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700450 offset += size;
John Stilesc0c51062020-12-03 17:16:29 -0500451 if ((field.fType->isArray() || field.fType->isStruct()) && offset % alignment != 0) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700452 offset += alignment - offset % alignment;
453 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700454 }
455}
456
Ethan Nicholase2c49992020-10-05 11:49:11 -0400457const Type& SPIRVCodeGenerator::getActualType(const Type& type) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500458 if (type.isFloat()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400459 return *fContext.fFloat_Type;
460 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500461 if (type.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400462 return *fContext.fInt_Type;
463 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500464 if (type.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400465 return *fContext.fUInt_Type;
466 }
John Stiles9aeed132020-11-24 17:36:06 -0500467 if (type.isMatrix() || type.isVector()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400468 if (type.componentType() == *fContext.fHalf_Type) {
469 return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
470 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400471 if (type.componentType() == *fContext.fShort_Type ||
472 type.componentType() == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400473 return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
474 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400475 if (type.componentType() == *fContext.fUShort_Type ||
476 type.componentType() == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400477 return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
478 }
479 }
480 return type;
481}
482
ethannicholasb3058bd2016-07-01 08:22:01 -0700483SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800484 return this->getType(type, fDefaultLayout);
485}
486
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400487SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400488 const Type& type = this->getActualType(rawType);
Jim Van Verthf3ec9832020-10-21 16:09:57 -0400489 String key = type.name();
John Stilesc0c51062020-12-03 17:16:29 -0500490 if (type.isStruct() || type.isArray()) {
Jim Van Verthf3ec9832020-10-21 16:09:57 -0400491 key += to_string((int)layout.fStd);
492 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800493 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700494 if (entry == fTypeMap.end()) {
495 SpvId result = this->nextId();
Ethan Nicholase6592142020-09-08 10:22:09 -0400496 switch (type.typeKind()) {
497 case Type::TypeKind::kScalar:
John Stiles4a7dc462020-11-25 11:08:08 -0500498 if (type.isBoolean()) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700499 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500500 } else if (type == *fContext.fInt_Type || type == *fContext.fShort_Type ||
501 type == *fContext.fIntLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700502 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500503 } else if (type == *fContext.fUInt_Type || type == *fContext.fUShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700504 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500505 } else if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type ||
506 type == *fContext.fFloatLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700507 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700508 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400509 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700510 }
511 break;
John Stilesfd41d872020-11-25 22:39:45 -0500512 case Type::TypeKind::kEnum:
513 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
514 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400515 case Type::TypeKind::kVector:
Greg Daniel64773e62016-11-22 09:44:03 -0500516 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800517 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700518 type.columns(), fConstantBuffer);
519 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400520 case Type::TypeKind::kMatrix:
Greg Daniel64773e62016-11-22 09:44:03 -0500521 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800522 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700523 type.columns(), fConstantBuffer);
524 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400525 case Type::TypeKind::kStruct:
ethannicholas8ac838d2016-11-22 08:39:36 -0800526 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700527 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400528 case Type::TypeKind::kArray: {
John Stiles21f5f452020-11-30 09:57:59 -0500529 if (!MemoryLayout::LayoutIsSupported(type)) {
530 fErrors.error(type.fOffset, "type '" + type.name() + "' is not permitted here");
531 return this->nextId();
532 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700533 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700534 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500535 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800536 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700537 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500538 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400539 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800540 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700541 } else {
John Stiles5570c512020-11-19 17:58:07 -0500542 // We shouldn't have any runtime-sized arrays right now
543 fErrors.error(type.fOffset, "runtime-sized arrays are not supported in SPIR-V");
Greg Daniel64773e62016-11-22 09:44:03 -0500544 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800545 this->getType(type.componentType(), layout),
546 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400547 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
548 (int32_t) layout.stride(type),
549 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700550 }
551 break;
552 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400553 case Type::TypeKind::kSampler: {
Greg Daniel64773e62016-11-22 09:44:03 -0500554 SpvId image = result;
555 if (SpvDimSubpassData != type.dimensions()) {
Stephen White792e2302019-08-09 13:33:51 -0400556 image = this->getType(type.textureType(), layout);
Greg Daniel64773e62016-11-22 09:44:03 -0500557 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400558 if (SpvDimBuffer == type.dimensions()) {
559 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
560 }
Greg Daniel64773e62016-11-22 09:44:03 -0500561 if (SpvDimSubpassData != type.dimensions()) {
562 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
563 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700564 break;
565 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400566 case Type::TypeKind::kSeparateSampler: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400567 this->writeInstruction(SpvOpTypeSampler, result, fConstantBuffer);
568 break;
569 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400570 case Type::TypeKind::kTexture: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400571 this->writeInstruction(SpvOpTypeImage, result,
572 this->getType(*fContext.fFloat_Type, layout),
John Stilesc0c51062020-12-03 17:16:29 -0500573 type.dimensions(), type.isDepth(), type.isArrayedTexture(),
Stephen White792e2302019-08-09 13:33:51 -0400574 type.isMultisampled(), type.isSampled() ? 1 : 2,
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400575 SpvImageFormatUnknown, fConstantBuffer);
576 fImageTypeMap[key] = result;
577 break;
578 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700579 default:
ethannicholasd598f792016-07-25 10:08:54 -0700580 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700581 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
582 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500583#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700584 ABORT("invalid type: %s", type.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500585#endif
ethannicholasb3058bd2016-07-01 08:22:01 -0700586 }
587 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800588 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700589 return result;
590 }
591 return entry->second;
592}
593
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400594SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400595 SkASSERT(type.typeKind() == Type::TypeKind::kSampler);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400596 this->getType(type);
597 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400598 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400599 return fImageTypeMap[key];
600}
601
ethannicholasd598f792016-07-25 10:08:54 -0700602SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400603 String key = to_string(this->getType(function.returnType())) + "(";
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400604 String separator;
Brian Osman5bf3e202020-10-13 10:34:18 -0400605 const std::vector<const Variable*>& parameters = function.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400606 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700607 key += separator;
608 separator = ", ";
Ethan Nicholased84b732020-10-08 11:45:44 -0400609 key += to_string(this->getType(parameters[i]->type()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700610 }
611 key += ")";
612 auto entry = fTypeMap.find(key);
613 if (entry == fTypeMap.end()) {
614 SpvId result = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -0400615 int32_t length = 3 + (int32_t) parameters.size();
616 SpvId returnType = this->getType(function.returnType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700617 std::vector<SpvId> parameterTypes;
Ethan Nicholased84b732020-10-08 11:45:44 -0400618 for (size_t i = 0; i < parameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500619 // glslang seems to treat all function arguments as pointers whether they need to be or
620 // not. I was initially puzzled by this until I ran bizarre failures with certain
621 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700622 // failure case:
623 //
624 // void sphere(float x) {
625 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500626 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700627 // void map() {
628 // sphere(1.0);
629 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500630 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700631 // void main() {
632 // for (int i = 0; i < 1; i++) {
633 // map();
634 // }
635 // }
636 //
Greg Daniel64773e62016-11-22 09:44:03 -0500637 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
638 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700639 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
640 // the spec makes this make sense.
641// if (is_out(function->fParameters[i])) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400642 parameterTypes.push_back(this->getPointerType(parameters[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -0700643 SpvStorageClassFunction));
644// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700645// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700646// }
647 }
648 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
649 this->writeWord(result, fConstantBuffer);
650 this->writeWord(returnType, fConstantBuffer);
651 for (SpvId id : parameterTypes) {
652 this->writeWord(id, fConstantBuffer);
653 }
654 fTypeMap[key] = result;
655 return result;
656 }
657 return entry->second;
658}
659
ethannicholas8ac838d2016-11-22 08:39:36 -0800660SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
661 return this->getPointerType(type, fDefaultLayout, storageClass);
662}
663
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400664SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700665 SpvStorageClass_ storageClass) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400666 const Type& type = this->getActualType(rawType);
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500667 String key = type.displayName() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700668 auto entry = fTypeMap.find(key);
669 if (entry == fTypeMap.end()) {
670 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500671 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700672 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700673 fTypeMap[key] = result;
674 return result;
675 }
676 return entry->second;
677}
678
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400679SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400680 switch (expr.kind()) {
681 case Expression::Kind::kBinary:
John Stiles81365af2020-08-18 09:24:00 -0400682 return this->writeBinaryExpression(expr.as<BinaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400683 case Expression::Kind::kBoolLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400684 return this->writeBoolLiteral(expr.as<BoolLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400685 case Expression::Kind::kConstructor:
John Stiles81365af2020-08-18 09:24:00 -0400686 return this->writeConstructor(expr.as<Constructor>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400687 case Expression::Kind::kIntLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400688 return this->writeIntLiteral(expr.as<IntLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400689 case Expression::Kind::kFieldAccess:
John Stiles81365af2020-08-18 09:24:00 -0400690 return this->writeFieldAccess(expr.as<FieldAccess>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400691 case Expression::Kind::kFloatLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400692 return this->writeFloatLiteral(expr.as<FloatLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400693 case Expression::Kind::kFunctionCall:
John Stiles81365af2020-08-18 09:24:00 -0400694 return this->writeFunctionCall(expr.as<FunctionCall>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400695 case Expression::Kind::kPrefix:
John Stiles81365af2020-08-18 09:24:00 -0400696 return this->writePrefixExpression(expr.as<PrefixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400697 case Expression::Kind::kPostfix:
John Stiles81365af2020-08-18 09:24:00 -0400698 return this->writePostfixExpression(expr.as<PostfixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400699 case Expression::Kind::kSwizzle:
John Stiles81365af2020-08-18 09:24:00 -0400700 return this->writeSwizzle(expr.as<Swizzle>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400701 case Expression::Kind::kVariableReference:
John Stiles81365af2020-08-18 09:24:00 -0400702 return this->writeVariableReference(expr.as<VariableReference>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400703 case Expression::Kind::kTernary:
John Stiles81365af2020-08-18 09:24:00 -0400704 return this->writeTernaryExpression(expr.as<TernaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400705 case Expression::Kind::kIndex:
John Stiles81365af2020-08-18 09:24:00 -0400706 return this->writeIndexExpression(expr.as<IndexExpression>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700707 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500708#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700709 ABORT("unsupported expression: %s", expr.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500710#endif
711 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700712 }
713 return -1;
714}
715
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400716SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400717 const FunctionDeclaration& function = c.function();
John Stiles8e3b6be2020-10-13 11:14:08 -0400718 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400719 auto intrinsic = fIntrinsicMap.find(function.name());
John Stiles93e661a2020-12-08 16:17:00 -0500720 if (intrinsic == fIntrinsicMap.end()) {
721 fErrors.error(c.fOffset, "unsupported intrinsic '" + function.description() + "'");
722 return -1;
723 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700724 int32_t intrinsicId;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400725 if (arguments.size() > 0) {
726 const Type& type = arguments[0]->type();
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400727 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
728 intrinsicId = std::get<1>(intrinsic->second);
729 } else if (is_signed(fContext, type)) {
730 intrinsicId = std::get<2>(intrinsic->second);
731 } else if (is_unsigned(fContext, type)) {
732 intrinsicId = std::get<3>(intrinsic->second);
733 } else if (is_bool(fContext, type)) {
734 intrinsicId = std::get<4>(intrinsic->second);
735 } else {
736 intrinsicId = std::get<1>(intrinsic->second);
737 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700738 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400739 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700740 }
741 switch (std::get<0>(intrinsic->second)) {
742 case kGLSL_STD_450_IntrinsicKind: {
743 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400744 std::vector<SpvId> argumentIds;
745 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400746 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400747 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400748 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400749 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400750 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700751 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400752 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400753 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700754 this->writeWord(result, out);
755 this->writeWord(fGLSLExtendedInstructions, out);
756 this->writeWord(intrinsicId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400757 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700758 this->writeWord(id, out);
759 }
760 return result;
761 }
762 case kSPIRV_IntrinsicKind: {
Brian Osman46787d52020-11-24 14:18:23 -0500763 // GLSL supports dot(float, float), but SPIR-V does not. Convert it to FMul
John Stiles9aeed132020-11-24 17:36:06 -0500764 if (intrinsicId == SpvOpDot && arguments[0]->type().isScalar()) {
Brian Osman46787d52020-11-24 14:18:23 -0500765 intrinsicId = SpvOpFMul;
766 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700767 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400768 std::vector<SpvId> argumentIds;
769 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400770 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400771 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400772 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400773 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400774 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700775 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400776 if (c.type() != *fContext.fVoid_Type) {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400777 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400778 this->writeWord(this->getType(c.type()), out);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400779 this->writeWord(result, out);
780 } else {
781 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
782 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400783 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700784 this->writeWord(id, out);
785 }
786 return result;
787 }
788 case kSpecial_IntrinsicKind:
789 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
790 default:
John Stiles93e661a2020-12-08 16:17:00 -0500791 fErrors.error(c.fOffset, "unsupported intrinsic '" + function.description() + "'");
792 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700793 }
794}
795
John Stiles8e3b6be2020-10-13 11:14:08 -0400796std::vector<SpvId> SPIRVCodeGenerator::vectorize(const ExpressionArray& args, OutputStream& out) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500797 int vectorSize = 0;
798 for (const auto& a : args) {
John Stiles9aeed132020-11-24 17:36:06 -0500799 if (a->type().isVector()) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500800 if (vectorSize) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400801 SkASSERT(a->type().columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500802 }
803 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400804 vectorSize = a->type().columns();
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500805 }
806 }
807 }
808 std::vector<SpvId> result;
John Stiles8e3b6be2020-10-13 11:14:08 -0400809 result.reserve(args.size());
Ethan Nicholas30d30222020-09-11 12:27:26 -0400810 for (const auto& arg : args) {
811 const Type& argType = arg->type();
812 SpvId raw = this->writeExpression(*arg, out);
John Stiles9aeed132020-11-24 17:36:06 -0500813 if (vectorSize && argType.isScalar()) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500814 SpvId vector = this->nextId();
815 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400816 this->writeWord(this->getType(argType.toCompound(fContext, vectorSize, 1)), out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500817 this->writeWord(vector, out);
818 for (int i = 0; i < vectorSize; i++) {
819 this->writeWord(raw, out);
820 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400821 this->writePrecisionModifier(argType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500822 result.push_back(vector);
823 } else {
824 result.push_back(raw);
825 }
826 }
827 return result;
828}
829
830void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
831 SpvId signedInst, SpvId unsignedInst,
832 const std::vector<SpvId>& args,
833 OutputStream& out) {
834 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
835 this->writeWord(this->getType(type), out);
836 this->writeWord(id, out);
837 this->writeWord(fGLSLExtendedInstructions, out);
838
839 if (is_float(fContext, type)) {
840 this->writeWord(floatInst, out);
841 } else if (is_signed(fContext, type)) {
842 this->writeWord(signedInst, out);
843 } else if (is_unsigned(fContext, type)) {
844 this->writeWord(unsignedInst, out);
845 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400846 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500847 }
848 for (SpvId a : args) {
849 this->writeWord(a, out);
850 }
851}
852
Greg Daniel64773e62016-11-22 09:44:03 -0500853SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400854 OutputStream& out) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400855 const ExpressionArray& arguments = c.arguments();
ethannicholasb3058bd2016-07-01 08:22:01 -0700856 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400857 const Type& callType = c.type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700858 switch (kind) {
859 case kAtan_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400860 std::vector<SpvId> argumentIds;
861 for (const std::unique_ptr<Expression>& arg : arguments) {
862 argumentIds.push_back(this->writeExpression(*arg, out));
ethannicholasb3058bd2016-07-01 08:22:01 -0700863 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400864 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400865 this->writeWord(this->getType(callType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700866 this->writeWord(result, out);
867 this->writeWord(fGLSLExtendedInstructions, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400868 this->writeWord(argumentIds.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
869 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700870 this->writeWord(id, out);
871 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400872 break;
873 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400874 case kSampledImage_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400875 SkASSERT(arguments.size() == 2);
876 SpvId img = this->writeExpression(*arguments[0], out);
877 SpvId sampler = this->writeExpression(*arguments[1], out);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400878 this->writeInstruction(SpvOpSampledImage,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400879 this->getType(callType),
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400880 result,
881 img,
882 sampler,
883 out);
884 break;
885 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400886 case kSubpassLoad_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400887 SpvId img = this->writeExpression(*arguments[0], out);
John Stiles8e3b6be2020-10-13 11:14:08 -0400888 ExpressionArray args;
John Stilesf4bda742020-10-14 16:57:41 -0400889 args.reserve_back(2);
John Stiles8e3b6be2020-10-13 11:14:08 -0400890 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
891 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
Ethan Nicholas30d30222020-09-11 12:27:26 -0400892 Constructor ctor(-1, fContext.fInt2_Type.get(), std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400893 SpvId coords = this->writeConstantVector(ctor);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400894 if (arguments.size() == 1) {
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400895 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400896 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400897 result,
898 img,
899 coords,
900 out);
901 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400902 SkASSERT(arguments.size() == 2);
903 SpvId sample = this->writeExpression(*arguments[1], out);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400904 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400905 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400906 result,
907 img,
908 coords,
909 SpvImageOperandsSampleMask,
910 sample,
911 out);
912 }
913 break;
914 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700915 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500916 SpvOp_ op = SpvOpImageSampleImplicitLod;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400917 const Type& arg1Type = arguments[1]->type();
918 switch (arguments[0]->type().dimensions()) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500919 case SpvDim1D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400920 if (arg1Type == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500921 op = SpvOpImageSampleProjImplicitLod;
922 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400923 SkASSERT(arg1Type == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500924 }
925 break;
926 case SpvDim2D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400927 if (arg1Type == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500928 op = SpvOpImageSampleProjImplicitLod;
929 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400930 SkASSERT(arg1Type == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500931 }
932 break;
933 case SpvDim3D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400934 if (arg1Type == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500935 op = SpvOpImageSampleProjImplicitLod;
936 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400937 SkASSERT(arg1Type == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500938 }
939 break;
940 case SpvDimCube: // fall through
941 case SpvDimRect: // fall through
942 case SpvDimBuffer: // fall through
943 case SpvDimSubpassData:
944 break;
945 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400946 SpvId type = this->getType(callType);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400947 SpvId sampler = this->writeExpression(*arguments[0], out);
948 SpvId uv = this->writeExpression(*arguments[1], out);
949 if (arguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500950 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700951 SpvImageOperandsBiasMask,
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400952 this->writeExpression(*arguments[2], out),
ethannicholasb3058bd2016-07-01 08:22:01 -0700953 out);
954 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400955 SkASSERT(arguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500956 if (fProgram.fSettings.fSharpenTextures) {
957 FloatLiteral lodBias(fContext, -1, -0.5);
958 this->writeInstruction(op, type, result, sampler, uv,
959 SpvImageOperandsBiasMask,
960 this->writeFloatLiteral(lodBias),
961 out);
962 } else {
963 this->writeInstruction(op, type, result, sampler, uv,
964 out);
965 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700966 }
967 break;
968 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500969 case kMod_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400970 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400971 SkASSERT(args.size() == 2);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400972 const Type& operandType = arguments[0]->type();
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500973 SpvOp_ op;
974 if (is_float(fContext, operandType)) {
975 op = SpvOpFMod;
976 } else if (is_signed(fContext, operandType)) {
977 op = SpvOpSMod;
978 } else if (is_unsigned(fContext, operandType)) {
979 op = SpvOpUMod;
980 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400981 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500982 return 0;
983 }
984 this->writeOpCode(op, 5, out);
985 this->writeWord(this->getType(operandType), out);
986 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500987 this->writeWord(args[0], out);
988 this->writeWord(args[1], out);
989 break;
990 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700991 case kDFdy_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400992 SpvId fn = this->writeExpression(*arguments[0], out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700993 this->writeOpCode(SpvOpDPdy, 4, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400994 this->writeWord(this->getType(callType), out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700995 this->writeWord(result, out);
996 this->writeWord(fn, out);
997 if (fProgram.fSettings.fFlipY) {
998 // Flipping Y also negates the Y derivatives.
999 SpvId flipped = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001000 this->writeInstruction(SpvOpFNegate, this->getType(callType), flipped, result,
1001 out);
1002 this->writePrecisionModifier(callType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -07001003 return flipped;
1004 }
1005 break;
1006 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001007 case kClamp_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001008 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001009 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001010 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001011 GLSLstd450UClamp, args, out);
1012 break;
1013 }
1014 case kMax_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001015 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001016 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001017 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMax, GLSLstd450SMax,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001018 GLSLstd450UMax, args, out);
1019 break;
1020 }
1021 case kMin_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001022 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001023 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001024 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMin, GLSLstd450SMin,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001025 GLSLstd450UMin, args, out);
1026 break;
1027 }
1028 case kMix_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001029 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001030 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001031 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMix, SpvOpUndef,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001032 SpvOpUndef, args, out);
1033 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -05001034 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001035 case kSaturate_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001036 SkASSERT(arguments.size() == 1);
John Stiles8e3b6be2020-10-13 11:14:08 -04001037 ExpressionArray finalArgs;
John Stilesf4bda742020-10-14 16:57:41 -04001038 finalArgs.reserve_back(3);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001039 finalArgs.push_back(arguments[0]->clone());
John Stiles8e3b6be2020-10-13 11:14:08 -04001040 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1041 /*value=*/0));
1042 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1043 /*value=*/1));
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001044 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001045 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001046 GLSLstd450UClamp, spvArgs, out);
1047 break;
1048 }
Brian Osman6ba3be12020-11-13 16:32:52 -05001049 case kSmoothStep_SpecialIntrinsic: {
1050 std::vector<SpvId> args = this->vectorize(arguments, out);
1051 SkASSERT(args.size() == 3);
1052 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450SmoothStep, SpvOpUndef,
1053 SpvOpUndef, args, out);
1054 break;
1055 }
1056 case kStep_SpecialIntrinsic: {
1057 std::vector<SpvId> args = this->vectorize(arguments, out);
1058 SkASSERT(args.size() == 2);
1059 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450Step, SpvOpUndef,
1060 SpvOpUndef, args, out);
1061 break;
1062 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001063 }
1064 return result;
1065}
1066
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001067SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001068 const FunctionDeclaration& function = c.function();
John Stiles8e3b6be2020-10-13 11:14:08 -04001069 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001070 const auto& entry = fFunctionMap.find(&function);
ethannicholasb3058bd2016-07-01 08:22:01 -07001071 if (entry == fFunctionMap.end()) {
1072 return this->writeIntrinsicCall(c, out);
1073 }
1074 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001075 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001076 std::vector<SpvId> argumentIds;
1077 for (size_t i = 0; i < arguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001078 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001079 // passed directly
1080 SpvId tmpVar;
1081 // if we need a temporary var to store this argument, this is the value to store in the var
1082 SpvId tmpValueId;
Ethan Nicholased84b732020-10-08 11:45:44 -04001083 if (is_out(*function.parameters()[i])) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001084 std::unique_ptr<LValue> lv = this->getLValue(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001085 SpvId ptr = lv->getPointer();
1086 if (ptr) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001087 argumentIds.push_back(ptr);
ethannicholasb3058bd2016-07-01 08:22:01 -07001088 continue;
1089 } else {
1090 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1091 // copy it into a temp, call the function, read the value out of the temp, and then
1092 // update the lvalue.
1093 tmpValueId = lv->load(out);
1094 tmpVar = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001095 lvalues.push_back(std::make_tuple(tmpVar, &arguments[i]->type(), std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001096 }
1097 } else {
1098 // see getFunctionType for an explanation of why we're always using pointer parameters
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001099 tmpValueId = this->writeExpression(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001100 tmpVar = this->nextId();
1101 }
Greg Daniel64773e62016-11-22 09:44:03 -05001102 this->writeInstruction(SpvOpVariable,
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001103 this->getPointerType(arguments[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001104 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001105 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001106 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001107 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001108 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001109 argumentIds.push_back(tmpVar);
ethannicholasb3058bd2016-07-01 08:22:01 -07001110 }
1111 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001112 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001113 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001114 this->writeWord(result, out);
1115 this->writeWord(entry->second, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001116 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001117 this->writeWord(id, out);
1118 }
1119 // now that the call is complete, we may need to update some lvalues with the new values of out
1120 // arguments
1121 for (const auto& tuple : lvalues) {
1122 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001123 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1124 out);
1125 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001126 std::get<2>(tuple)->store(load, out);
1127 }
1128 return result;
1129}
1130
ethannicholasf789b382016-08-03 12:43:36 -07001131SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001132 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001133 SkASSERT(type.isVector() && c.isCompileTimeConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001134 SpvId result = this->nextId();
1135 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001136 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1137 arguments.push_back(this->writeExpression(*arg, fConstantBuffer));
ethannicholasb3058bd2016-07-01 08:22:01 -07001138 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001139 SpvId typeId = this->getType(type);
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001140 if (c.arguments().size() == 1) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001141 // with a single argument, a vector will have all of its entries equal to the argument
Ethan Nicholas30d30222020-09-11 12:27:26 -04001142 this->writeOpCode(SpvOpConstantComposite, 3 + type.columns(), fConstantBuffer);
1143 this->writeWord(typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001144 this->writeWord(result, fConstantBuffer);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001145 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001146 this->writeWord(arguments[0], fConstantBuffer);
1147 }
1148 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001149 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.arguments().size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001150 fConstantBuffer);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001151 this->writeWord(typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001152 this->writeWord(result, fConstantBuffer);
1153 for (SpvId id : arguments) {
1154 this->writeWord(id, fConstantBuffer);
1155 }
1156 }
1157 return result;
1158}
1159
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001160SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001161 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001162 SkASSERT(c.arguments().size() == 1);
1163 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001164 SkASSERT(constructorType.isFloat());
1165 SkASSERT(argType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001166 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001167 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001168 if (argType.isSigned()) {
1169 this->writeInstruction(SpvOpConvertSToF, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001170 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001171 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001172 SkASSERT(argType.isUnsigned());
1173 this->writeInstruction(SpvOpConvertUToF, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001174 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001175 }
1176 return result;
1177}
1178
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001179SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001180 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001181 SkASSERT(c.arguments().size() == 1);
1182 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001183 SkASSERT(constructorType.isSigned());
1184 SkASSERT(argType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001185 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001186 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001187 if (argType.isFloat()) {
1188 this->writeInstruction(SpvOpConvertFToS, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001189 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001190 }
1191 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001192 SkASSERT(argType.isUnsigned());
1193 this->writeInstruction(SpvOpBitcast, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001194 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001195 }
1196 return result;
1197}
1198
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001199SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001200 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001201 SkASSERT(c.arguments().size() == 1);
1202 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001203 SkASSERT(constructorType.isUnsigned());
1204 SkASSERT(argType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001205 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001206 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001207 if (argType.isFloat()) {
1208 this->writeInstruction(SpvOpConvertFToU, this->getType(constructorType), result, parameter,
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001209 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001210 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001211 SkASSERT(argType.isSigned());
1212 this->writeInstruction(SpvOpBitcast, this->getType(constructorType), result, parameter,
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001213 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001214 }
1215 return result;
1216}
1217
Ethan Nicholas84645e32017-02-09 13:57:14 -05001218void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001219 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001220 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001221 SpvId zeroId = this->writeFloatLiteral(zero);
1222 std::vector<SpvId> columnIds;
1223 for (int column = 0; column < type.columns(); column++) {
1224 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1225 out);
1226 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1227 out);
1228 SpvId columnId = this->nextId();
1229 this->writeWord(columnId, out);
1230 columnIds.push_back(columnId);
1231 for (int row = 0; row < type.columns(); row++) {
1232 this->writeWord(row == column ? diagonal : zeroId, out);
1233 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001234 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001235 }
1236 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1237 out);
1238 this->writeWord(this->getType(type), out);
1239 this->writeWord(id, out);
John Stilesf621e232020-08-25 13:33:02 -04001240 for (SpvId columnId : columnIds) {
1241 this->writeWord(columnId, out);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001242 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001243 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001244}
1245
1246void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001247 const Type& dstType, OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05001248 SkASSERT(srcType.isMatrix());
1249 SkASSERT(dstType.isMatrix());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001250 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001251 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1252 srcType.rows(),
1253 1));
1254 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1255 dstType.rows(),
1256 1));
1257 SpvId zeroId;
1258 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001259 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001260 zeroId = this->writeFloatLiteral(zero);
1261 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001262 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001263 zeroId = this->writeIntLiteral(zero);
1264 } else {
1265 ABORT("unsupported matrix component type");
1266 }
1267 SpvId zeroColumn = 0;
1268 SpvId columns[4];
1269 for (int i = 0; i < dstType.columns(); i++) {
1270 if (i < srcType.columns()) {
1271 // we're still inside the src matrix, copy the column
1272 SpvId srcColumn = this->nextId();
1273 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001274 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001275 SpvId dstColumn;
1276 if (srcType.rows() == dstType.rows()) {
1277 // columns are equal size, don't need to do anything
1278 dstColumn = srcColumn;
1279 }
1280 else if (dstType.rows() > srcType.rows()) {
1281 // dst column is bigger, need to zero-pad it
1282 dstColumn = this->nextId();
1283 int delta = dstType.rows() - srcType.rows();
1284 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1285 this->writeWord(dstColumnType, out);
1286 this->writeWord(dstColumn, out);
1287 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001288 for (int j = 0; j < delta; ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001289 this->writeWord(zeroId, out);
1290 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001291 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001292 }
1293 else {
1294 // dst column is smaller, need to swizzle the src column
1295 dstColumn = this->nextId();
1296 int count = dstType.rows();
1297 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1298 this->writeWord(dstColumnType, out);
1299 this->writeWord(dstColumn, out);
1300 this->writeWord(srcColumn, out);
1301 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001302 for (int j = 0; j < count; j++) {
1303 this->writeWord(j, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001304 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001305 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001306 }
1307 columns[i] = dstColumn;
1308 } else {
1309 // we're past the end of the src matrix, need a vector of zeroes
1310 if (!zeroColumn) {
1311 zeroColumn = this->nextId();
1312 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1313 this->writeWord(dstColumnType, out);
1314 this->writeWord(zeroColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001315 for (int j = 0; j < dstType.rows(); ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001316 this->writeWord(zeroId, out);
1317 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001318 this->writePrecisionModifier(dstType, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001319 }
1320 columns[i] = zeroColumn;
1321 }
1322 }
1323 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1324 this->writeWord(this->getType(dstType), out);
1325 this->writeWord(id, out);
1326 for (int i = 0; i < dstType.columns(); i++) {
1327 this->writeWord(columns[i], out);
1328 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001329 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001330}
1331
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001332void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1333 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001334 std::vector<SpvId>* columnIds,
1335 int* currentCount, int rows, SpvId entry,
1336 OutputStream& out) {
1337 SkASSERT(*currentCount < rows);
1338 ++(*currentCount);
1339 currentColumn->push_back(entry);
1340 if (*currentCount == rows) {
1341 *currentCount = 0;
1342 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1343 this->writeWord(columnType, out);
1344 SpvId columnId = this->nextId();
1345 this->writeWord(columnId, out);
1346 columnIds->push_back(columnId);
1347 for (SpvId id : *currentColumn) {
1348 this->writeWord(id, out);
1349 }
1350 currentColumn->clear();
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001351 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001352 }
1353}
1354
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001355SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001356 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001357 SkASSERT(type.isMatrix());
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001358 SkASSERT(c.arguments().size() > 0);
1359 const Type& arg0Type = c.arguments()[0]->type();
ethannicholasb3058bd2016-07-01 08:22:01 -07001360 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1361 // an instruction
1362 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001363 for (size_t i = 0; i < c.arguments().size(); i++) {
1364 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001365 }
1366 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001367 int rows = type.rows();
1368 int columns = type.columns();
John Stiles9aeed132020-11-24 17:36:06 -05001369 if (arguments.size() == 1 && arg0Type.isScalar()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001370 this->writeUniformScaleMatrix(result, arguments[0], type, out);
John Stiles9aeed132020-11-24 17:36:06 -05001371 } else if (arguments.size() == 1 && arg0Type.isMatrix()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001372 this->writeMatrixCopy(result, arguments[0], arg0Type, type, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001373 } else if (arguments.size() == 1 &&
John Stiles9aeed132020-11-24 17:36:06 -05001374 arg0Type.isVector()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001375 SkASSERT(type.rows() == 2 && type.columns() == 2);
1376 SkASSERT(arg0Type.columns() == 4);
1377 SpvId componentType = this->getType(type.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001378 SpvId v[4];
1379 for (int i = 0; i < 4; ++i) {
1380 v[i] = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001381 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i,
1382 out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001383 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001384 SpvId columnType = this->getType(type.componentType().toCompound(fContext, 2, 1));
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001385 SpvId column1 = this->nextId();
1386 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1387 SpvId column2 = this->nextId();
1388 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001389 this->writeInstruction(SpvOpCompositeConstruct, this->getType(type), result, column1,
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001390 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001391 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001392 SpvId columnType = this->getType(type.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001393 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001394 // ids of vectors and scalars we have written to the current column so far
1395 std::vector<SpvId> currentColumn;
1396 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001397 int currentCount = 0;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001398 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001399 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001400 const Type& argType = c.arguments()[i]->type();
John Stiles9aeed132020-11-24 17:36:06 -05001401 if (currentCount == 0 && argType.isVector() &&
Ethan Nicholas30d30222020-09-11 12:27:26 -04001402 argType.columns() == type.rows()) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001403 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001404 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001405 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001406 if (argType.columns() == 1) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001407 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1408 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001409 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001410 SpvId componentType = this->getType(argType.componentType());
1411 for (int j = 0; j < argType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001412 SpvId swizzle = this->nextId();
1413 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1414 arguments[i], j, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001415 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1416 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001417 }
1418 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001419 }
1420 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001421 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001422 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001423 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001424 this->writeWord(result, out);
1425 for (SpvId id : columnIds) {
1426 this->writeWord(id, out);
1427 }
1428 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001429 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001430 return result;
1431}
1432
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001433SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001434 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001435 SkASSERT(type.isVector());
Brian Osmanb6b95732020-06-30 11:44:27 -04001436 if (c.isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001437 return this->writeConstantVector(c);
1438 }
1439 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1440 // an instruction
1441 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001442 for (size_t i = 0; i < c.arguments().size(); i++) {
1443 const Type& argType = c.arguments()[i]->type();
John Stiles9aeed132020-11-24 17:36:06 -05001444 if (argType.isVector()) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001445 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1446 // extract the components and convert them in that case manually. On top of that,
1447 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1448 // doesn't handle vector arguments at all, so we always extract vector components and
1449 // pass them into OpCreateComposite individually.
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001450 SpvId vec = this->writeExpression(*c.arguments()[i], out);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001451 SpvOp_ op = SpvOpUndef;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001452 const Type& src = argType.componentType();
1453 const Type& dst = type.componentType();
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001454 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1455 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001456 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001457 return vec;
1458 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001459 } else if (src == *fContext.fInt_Type ||
1460 src == *fContext.fShort_Type ||
1461 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001462 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001463 } else if (src == *fContext.fUInt_Type ||
1464 src == *fContext.fUShort_Type ||
1465 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001466 op = SpvOpConvertUToF;
1467 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001468 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001469 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001470 } else if (dst == *fContext.fInt_Type ||
1471 dst == *fContext.fShort_Type ||
1472 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001473 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1474 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001475 } else if (src == *fContext.fInt_Type ||
1476 src == *fContext.fShort_Type ||
1477 src == *fContext.fByte_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001478 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001479 return vec;
1480 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001481 } else if (src == *fContext.fUInt_Type ||
1482 src == *fContext.fUShort_Type ||
1483 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001484 op = SpvOpBitcast;
1485 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001486 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001487 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001488 } else if (dst == *fContext.fUInt_Type ||
1489 dst == *fContext.fUShort_Type ||
1490 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001491 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1492 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001493 } else if (src == *fContext.fInt_Type ||
1494 src == *fContext.fShort_Type ||
1495 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001496 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001497 } else if (src == *fContext.fUInt_Type ||
1498 src == *fContext.fUShort_Type ||
1499 src == *fContext.fUByte_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001500 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001501 return vec;
1502 }
1503 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001504 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001505 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001506 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001507 for (int j = 0; j < argType.columns(); j++) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001508 SpvId swizzle = this->nextId();
1509 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1510 out);
1511 if (op != SpvOpUndef) {
1512 SpvId cast = this->nextId();
1513 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1514 arguments.push_back(cast);
1515 } else {
1516 arguments.push_back(swizzle);
1517 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001518 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001519 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001520 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001521 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001522 }
1523 SpvId result = this->nextId();
John Stiles9aeed132020-11-24 17:36:06 -05001524 if (arguments.size() == 1 && c.arguments()[0]->type().isScalar()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001525 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(), out);
1526 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001527 this->writeWord(result, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001528 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001529 this->writeWord(arguments[0], out);
1530 }
1531 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001532 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001533 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001534 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001535 this->writeWord(result, out);
1536 for (SpvId id : arguments) {
1537 this->writeWord(id, out);
1538 }
1539 }
1540 return result;
1541}
1542
Ethan Nicholasbd553222017-07-18 15:54:59 -04001543SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001544 const Type& type = c.type();
John Stilesc0c51062020-12-03 17:16:29 -05001545 SkASSERT(type.isArray());
Ethan Nicholasbd553222017-07-18 15:54:59 -04001546 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1547 // an instruction
1548 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001549 for (size_t i = 0; i < c.arguments().size(); i++) {
1550 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholasbd553222017-07-18 15:54:59 -04001551 }
1552 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001553 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.arguments().size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001554 this->writeWord(this->getType(type), out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001555 this->writeWord(result, out);
1556 for (SpvId id : arguments) {
1557 this->writeWord(id, out);
1558 }
1559 return result;
1560}
1561
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001562SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001563 const Type& type = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001564 if (c.arguments().size() == 1 &&
1565 this->getActualType(type) == this->getActualType(c.arguments()[0]->type())) {
1566 return this->writeExpression(*c.arguments()[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001567 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001568 if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001569 return this->writeFloatConstructor(c, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001570 } else if (type == *fContext.fInt_Type ||
1571 type == *fContext.fShort_Type ||
1572 type == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001573 return this->writeIntConstructor(c, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001574 } else if (type == *fContext.fUInt_Type ||
1575 type == *fContext.fUShort_Type ||
1576 type == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001577 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001578 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001579 switch (type.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001580 case Type::TypeKind::kVector:
ethannicholasb3058bd2016-07-01 08:22:01 -07001581 return this->writeVectorConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001582 case Type::TypeKind::kMatrix:
ethannicholasb3058bd2016-07-01 08:22:01 -07001583 return this->writeMatrixConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001584 case Type::TypeKind::kArray:
Ethan Nicholasbd553222017-07-18 15:54:59 -04001585 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001586 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001587#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07001588 ABORT("unsupported constructor: %s", c.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001589#endif
1590 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001591 }
1592}
1593
1594SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1595 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001596 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001597 return SpvStorageClassInput;
1598 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001599 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001600 return SpvStorageClassOutput;
1601 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001602 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001603 return SpvStorageClassPushConstant;
1604 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001605 return SpvStorageClassUniform;
1606 } else {
1607 return SpvStorageClassFunction;
1608 }
1609}
1610
ethannicholasf789b382016-08-03 12:43:36 -07001611SpvStorageClass_ get_storage_class(const Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001612 switch (expr.kind()) {
1613 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -04001614 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001615 if (var.storage() != Variable::Storage::kGlobal) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001616 return SpvStorageClassFunction;
1617 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001618 SpvStorageClass_ result = get_storage_class(var.modifiers());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001619 if (result == SpvStorageClassFunction) {
1620 result = SpvStorageClassPrivate;
1621 }
1622 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001623 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001624 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001625 return get_storage_class(*expr.as<FieldAccess>().base());
Ethan Nicholase6592142020-09-08 10:22:09 -04001626 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001627 return get_storage_class(*expr.as<IndexExpression>().base());
ethannicholasb3058bd2016-07-01 08:22:01 -07001628 default:
1629 return SpvStorageClassFunction;
1630 }
1631}
1632
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001633std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001634 std::vector<SpvId> chain;
Ethan Nicholase6592142020-09-08 10:22:09 -04001635 switch (expr.kind()) {
1636 case Expression::Kind::kIndex: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001637 IndexExpression& indexExpr = (IndexExpression&) expr;
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001638 chain = this->getAccessChain(*indexExpr.base(), out);
1639 chain.push_back(this->writeExpression(*indexExpr.index(), out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001640 break;
1641 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001642 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001643 FieldAccess& fieldExpr = (FieldAccess&) expr;
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001644 chain = this->getAccessChain(*fieldExpr.base(), out);
1645 IntLiteral index(fContext, -1, fieldExpr.fieldIndex());
ethannicholasb3058bd2016-07-01 08:22:01 -07001646 chain.push_back(this->writeIntLiteral(index));
1647 break;
1648 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001649 default: {
1650 SpvId id = this->getLValue(expr, out)->getPointer();
1651 SkASSERT(id != 0);
1652 chain.push_back(id);
1653 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001654 }
1655 return chain;
1656}
1657
1658class PointerLValue : public SPIRVCodeGenerator::LValue {
1659public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001660 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1661 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001662 : fGen(gen)
1663 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001664 , fType(type)
1665 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001666
John Stiles1cf2c8d2020-08-13 22:58:04 -04001667 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001668 return fPointer;
1669 }
1670
John Stiles1cf2c8d2020-08-13 22:58:04 -04001671 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001672 SpvId result = fGen.nextId();
1673 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001674 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001675 return result;
1676 }
1677
John Stiles1cf2c8d2020-08-13 22:58:04 -04001678 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001679 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1680 }
1681
1682private:
1683 SPIRVCodeGenerator& fGen;
1684 const SpvId fPointer;
1685 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001686 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001687};
1688
1689class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1690public:
John Stiles750109b2020-10-30 13:45:46 -04001691 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const ComponentArray& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001692 const Type& baseType, const Type& swizzleType,
1693 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001694 : fGen(gen)
1695 , fVecPointer(vecPointer)
1696 , fComponents(components)
1697 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001698 , fSwizzleType(swizzleType)
1699 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001700
John Stiles1cf2c8d2020-08-13 22:58:04 -04001701 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001702 return 0;
1703 }
1704
John Stiles1cf2c8d2020-08-13 22:58:04 -04001705 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001706 SpvId base = fGen.nextId();
1707 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001708 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001709 SpvId result = fGen.nextId();
1710 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1711 fGen.writeWord(fGen.getType(fSwizzleType), out);
1712 fGen.writeWord(result, out);
1713 fGen.writeWord(base, out);
1714 fGen.writeWord(base, out);
1715 for (int component : fComponents) {
1716 fGen.writeWord(component, out);
1717 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001718 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001719 return result;
1720 }
1721
John Stiles1cf2c8d2020-08-13 22:58:04 -04001722 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001723 // use OpVectorShuffle to mix and match the vector components. We effectively create
1724 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001725 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001726 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001727 // float3L = ...;
1728 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001729 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001730 // 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 -07001731 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1732 // (3, 1, 4).
1733 SpvId base = fGen.nextId();
1734 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1735 SpvId shuffle = fGen.nextId();
1736 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1737 fGen.writeWord(fGen.getType(fBaseType), out);
1738 fGen.writeWord(shuffle, out);
1739 fGen.writeWord(base, out);
1740 fGen.writeWord(value, out);
1741 for (int i = 0; i < fBaseType.columns(); i++) {
1742 // current offset into the virtual vector, defaults to pulling the unmodified
1743 // value from the left side
1744 int offset = i;
1745 // check to see if we are writing this component
1746 for (size_t j = 0; j < fComponents.size(); j++) {
1747 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001748 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001749 // the correct component of the right side instead of preserving the
1750 // value from the left
1751 offset = (int) (j + fBaseType.columns());
1752 break;
1753 }
1754 }
1755 fGen.writeWord(offset, out);
1756 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001757 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001758 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1759 }
1760
1761private:
1762 SPIRVCodeGenerator& fGen;
1763 const SpvId fVecPointer;
John Stiles750109b2020-10-30 13:45:46 -04001764 const ComponentArray& fComponents;
ethannicholasb3058bd2016-07-01 08:22:01 -07001765 const Type& fBaseType;
1766 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001767 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001768};
1769
Greg Daniel64773e62016-11-22 09:44:03 -05001770std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001771 OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001772 const Type& type = expr.type();
1773 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
Ethan Nicholase6592142020-09-08 10:22:09 -04001774 switch (expr.kind()) {
1775 case Expression::Kind::kVariableReference: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001776 SpvId typeId;
Ethan Nicholas78686922020-10-08 06:46:27 -04001777 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001778 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001779 typeId = this->getType(Type("sk_in", Type::TypeKind::kArray,
1780 var.type().componentType(), fSkInCount));
Ethan Nicholas5226b772018-05-03 16:20:41 -04001781 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001782 typeId = this->getType(type);
Ethan Nicholas5226b772018-05-03 16:20:41 -04001783 }
ethannicholasd598f792016-07-25 10:08:54 -07001784 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001785 SkASSERT(entry != fVariableMap.end());
John Stiles5570c512020-11-19 17:58:07 -05001786 return std::make_unique<PointerLValue>(*this, entry->second, typeId, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001787 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001788 case Expression::Kind::kIndex: // fall through
1789 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001790 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1791 SpvId member = this->nextId();
1792 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001793 this->writeWord(this->getPointerType(type, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001794 this->writeWord(member, out);
1795 for (SpvId idx : chain) {
1796 this->writeWord(idx, out);
1797 }
John Stiles5570c512020-11-19 17:58:07 -05001798 return std::make_unique<PointerLValue>(*this, member, this->getType(type), precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001799 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001800 case Expression::Kind::kSwizzle: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001801 Swizzle& swizzle = (Swizzle&) expr;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001802 size_t count = swizzle.components().size();
1803 SpvId base = this->getLValue(*swizzle.base(), out)->getPointer();
John Stiles5570c512020-11-19 17:58:07 -05001804 if (!base) {
1805 fErrors.error(swizzle.fOffset, "unable to retrieve lvalue from swizzle");
1806 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001807 if (count == 1) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001808 IntLiteral index(fContext, -1, swizzle.components()[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001809 SpvId member = this->nextId();
1810 this->writeInstruction(SpvOpAccessChain,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001811 this->getPointerType(type,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001812 get_storage_class(*swizzle.base())),
Greg Daniel64773e62016-11-22 09:44:03 -05001813 member,
1814 base,
1815 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001816 out);
John Stiles5570c512020-11-19 17:58:07 -05001817 return std::make_unique<PointerLValue>(*this, member, this->getType(type),
1818 precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001819 } else {
John Stiles5570c512020-11-19 17:58:07 -05001820 return std::make_unique<SwizzleLValue>(*this, base, swizzle.components(),
1821 swizzle.base()->type(), type, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001822 }
1823 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001824 case Expression::Kind::kTernary: {
Ethan Nicholasa583b812018-01-18 13:32:11 -05001825 TernaryExpression& t = (TernaryExpression&) expr;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001826 SpvId test = this->writeExpression(*t.test(), out);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001827 SpvId end = this->nextId();
1828 SpvId ifTrueLabel = this->nextId();
1829 SpvId ifFalseLabel = this->nextId();
1830 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1831 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1832 this->writeLabel(ifTrueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04001833 SpvId ifTrue = this->getLValue(*t.ifTrue(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001834 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001835 this->writeInstruction(SpvOpBranch, end, out);
1836 ifTrueLabel = fCurrentBlock;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001837 SpvId ifFalse = this->getLValue(*t.ifFalse(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001838 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001839 ifFalseLabel = fCurrentBlock;
1840 this->writeInstruction(SpvOpBranch, end, out);
1841 SpvId result = this->nextId();
1842 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1843 ifTrueLabel, ifFalse, ifFalseLabel, out);
John Stiles5570c512020-11-19 17:58:07 -05001844 return std::make_unique<PointerLValue>(*this, result, this->getType(type), precision);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001845 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001846 default: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001847 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001848 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001849 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1850 // caught by IRGenerator
1851 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001852 SpvId pointerType = this->getPointerType(type, SpvStorageClassFunction);
1853 this->writeInstruction(SpvOpVariable, pointerType, result, SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001854 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001855 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
John Stiles5570c512020-11-19 17:58:07 -05001856 return std::make_unique<PointerLValue>(*this, result, this->getType(type), precision);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001857 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001858 }
1859}
1860
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001861SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001862 SpvId result = this->nextId();
Ethan Nicholas78686922020-10-08 06:46:27 -04001863 auto entry = fVariableMap.find(ref.variable());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001864 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001865 SpvId var = entry->second;
Ethan Nicholas78686922020-10-08 06:46:27 -04001866 this->writeInstruction(SpvOpLoad, this->getType(ref.variable()->type()), result, var, out);
1867 this->writePrecisionModifier(ref.variable()->type(), result);
1868 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
Greg Daniela85e4bf2020-06-17 16:32:45 -04001869 (fProgram.fSettings.fFlipY || fProgram.fSettings.fInverseW)) {
1870 // The x component never changes, so just grab it
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001871 SpvId xId = this->nextId();
1872 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1873 result, 0, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001874
1875 // Calculate the y component which may need to be flipped
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001876 SpvId rawYId = this->nextId();
1877 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1878 result, 1, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001879 SpvId flippedYId = 0;
1880 if (fProgram.fSettings.fFlipY) {
1881 // need to remap to a top-left coordinate system
1882 if (fRTHeightStructId == (SpvId)-1) {
1883 // height variable hasn't been written yet
Greg Daniela85e4bf2020-06-17 16:32:45 -04001884 SkASSERT(fRTHeightFieldIndex == (SpvId)-1);
1885 std::vector<Type::Field> fields;
John Stiles5570c512020-11-19 17:58:07 -05001886 if (fProgram.fSettings.fRTHeightOffset < 0) {
1887 fErrors.error(ref.fOffset, "RTHeightOffset is negative");
1888 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001889 fields.emplace_back(
1890 Modifiers(Layout(0, -1, fProgram.fSettings.fRTHeightOffset, -1, -1, -1, -1,
1891 -1, Layout::Format::kUnspecified,
1892 Layout::kUnspecified_Primitive, 1, -1, "", "",
1893 Layout::kNo_Key, Layout::CType::kDefault),
1894 0),
1895 SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1896 StringFragment name("sksl_synthetic_uniforms");
1897 Type intfStruct(-1, name, fields);
1898
1899 int binding = fProgram.fSettings.fRTHeightBinding;
John Stiles5570c512020-11-19 17:58:07 -05001900 if (binding == -1) {
1901 fErrors.error(ref.fOffset, "layout(binding=...) is required in SPIR-V");
1902 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001903 int set = fProgram.fSettings.fRTHeightSet;
John Stiles5570c512020-11-19 17:58:07 -05001904 if (set == -1) {
1905 fErrors.error(ref.fOffset, "layout(set=...) is required in SPIR-V");
1906 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001907 Layout layout(0, -1, -1, binding, -1, set, -1, -1, Layout::Format::kUnspecified,
1908 Layout::kUnspecified_Primitive, -1, -1, "", "", Layout::kNo_Key,
1909 Layout::CType::kDefault);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001910 Modifiers modifiers(layout, Modifiers::kUniform_Flag);
John Stiles3ae071e2020-08-05 15:29:29 -04001911 const Variable* intfVar = fSynthetics.takeOwnershipOfSymbol(
1912 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -05001913 fProgram.fModifiers->addToPool(modifiers),
John Stiles3ae071e2020-08-05 15:29:29 -04001914 name,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001915 &intfStruct,
Brian Osman3887a012020-09-30 13:22:27 -04001916 /*builtin=*/false,
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001917 Variable::Storage::kGlobal));
John Stilesd39aec02020-12-03 10:42:26 -05001918 InterfaceBlock intf(/*offset=*/-1, intfVar, name,
1919 /*instanceName=*/"", /*arraySize=*/0,
John Stiles7c3515b2020-10-16 18:38:39 -04001920 std::make_shared<SymbolTable>(&fErrors, /*builtin=*/false));
Stephen White88574972020-06-23 19:09:29 -04001921
1922 fRTHeightStructId = this->writeInterfaceBlock(intf, false);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001923 fRTHeightFieldIndex = 0;
Jim Van Verthf3ec9832020-10-21 16:09:57 -04001924 fRTHeightStorageClass = SpvStorageClassUniform;
Greg Daniela85e4bf2020-06-17 16:32:45 -04001925 }
1926 SkASSERT(fRTHeightFieldIndex != (SpvId)-1);
1927
1928 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1929 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1930 SpvId heightPtr = this->nextId();
1931 this->writeOpCode(SpvOpAccessChain, 5, out);
Jim Van Verthf3ec9832020-10-21 16:09:57 -04001932 this->writeWord(this->getPointerType(*fContext.fFloat_Type, fRTHeightStorageClass),
Greg Daniela85e4bf2020-06-17 16:32:45 -04001933 out);
1934 this->writeWord(heightPtr, out);
1935 this->writeWord(fRTHeightStructId, out);
1936 this->writeWord(fieldIndexId, out);
1937 SpvId heightRead = this->nextId();
1938 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1939 heightPtr, out);
1940
1941 flippedYId = this->nextId();
1942 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
1943 heightRead, rawYId, out);
1944 }
1945
1946 // The z component will always be zero so we just get an id to the 0 literal
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001947 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001948 SpvId zeroId = writeFloatLiteral(zero);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001949
1950 // Calculate the w component which may need to be inverted
1951 SpvId rawWId = this->nextId();
1952 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawWId,
Ethan Nicholas20798e52018-12-04 12:30:50 -05001953 result, 3, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001954 SpvId invWId = 0;
1955 if (fProgram.fSettings.fInverseW) {
1956 // We need to invert w
1957 FloatLiteral one(fContext, -1, 1.0);
1958 SpvId oneId = writeFloatLiteral(one);
1959 invWId = this->nextId();
1960 this->writeInstruction(SpvOpFDiv, this->getType(*fContext.fFloat_Type), invWId, oneId,
1961 rawWId, out);
1962 }
1963
1964 // Fill in the new fragcoord with the components from above
1965 SpvId adjusted = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001966 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001967 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001968 this->writeWord(adjusted, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001969 this->writeWord(xId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001970 if (fProgram.fSettings.fFlipY) {
1971 this->writeWord(flippedYId, out);
1972 } else {
1973 this->writeWord(rawYId, out);
1974 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001975 this->writeWord(zeroId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001976 if (fProgram.fSettings.fInverseW) {
1977 this->writeWord(invWId, out);
1978 } else {
1979 this->writeWord(rawWId, out);
1980 }
1981
1982 return adjusted;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001983 }
Ethan Nicholas78686922020-10-08 06:46:27 -04001984 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
Chris Daltonb91c4662018-08-01 10:46:22 -06001985 !fProgram.fSettings.fFlipY) {
1986 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1987 // the default convention of "counter-clockwise face is front".
1988 SpvId inverse = this->nextId();
1989 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1990 result, out);
1991 return inverse;
1992 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001993 return result;
1994}
1995
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001996SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05001997 if (expr.base()->type().isVector()) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001998 SpvId base = this->writeExpression(*expr.base(), out);
1999 SpvId index = this->writeExpression(*expr.index(), out);
Ethan Nicholasa9a06902019-01-07 14:42:40 -05002000 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002001 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.type()), result, base,
Ethan Nicholasa9a06902019-01-07 14:42:40 -05002002 index, out);
2003 return result;
2004 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002005 return getLValue(expr, out)->load(out);
2006}
2007
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002008SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002009 return getLValue(f, out)->load(out);
2010}
2011
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002012SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002013 SpvId base = this->writeExpression(*swizzle.base(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002014 SpvId result = this->nextId();
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002015 size_t count = swizzle.components().size();
ethannicholasb3058bd2016-07-01 08:22:01 -07002016 if (count == 1) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002017 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.type()), result, base,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002018 swizzle.components()[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002019 } else {
2020 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002021 this->writeWord(this->getType(swizzle.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002022 this->writeWord(result, out);
2023 this->writeWord(base, out);
Brian Osman25647672020-09-15 15:16:56 -04002024 this->writeWord(base, out);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002025 for (int component : swizzle.components()) {
Brian Osman25647672020-09-15 15:16:56 -04002026 this->writeWord(component, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002027 }
2028 }
2029 return result;
2030}
2031
Greg Daniel64773e62016-11-22 09:44:03 -05002032SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
2033 const Type& operandType, SpvId lhs,
2034 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002035 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002036 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002037 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002038 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002039 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002040 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002041 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002042 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
John Stiles123501f2020-12-09 10:08:13 -05002043 } else if (is_bool(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002044 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002045 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07002046 } else {
John Stiles123501f2020-12-09 10:08:13 -05002047 fErrors.error(operandType.fOffset,
2048 "unsupported operand for binary expression: " + operandType.description());
2049 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002050 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04002051 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002052 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
2053 fDecorationBuffer);
2054 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002055 return result;
2056}
2057
Ethan Nicholas48e24052018-03-14 13:51:39 -04002058SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
2059 OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05002060 if (operandType.isVector()) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002061 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04002062 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002063 return result;
2064 }
2065 return id;
2066}
2067
Ethan Nicholas68990be2017-07-13 09:36:52 -04002068SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
2069 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002070 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04002071 OutputStream& out) {
2072 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
John Stiles9aeed132020-11-24 17:36:06 -05002073 SkASSERT(operandType.isMatrix());
Ethan Nicholas0df21132018-07-10 09:37:51 -04002074 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2075 operandType.rows(),
2076 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04002077 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002078 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04002079 1));
2080 SpvId boolType = this->getType(*fContext.fBool_Type);
2081 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04002082 for (int i = 0; i < operandType.columns(); i++) {
2083 SpvId columnL = this->nextId();
2084 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2085 SpvId columnR = this->nextId();
2086 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002087 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002088 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
2089 SpvId merge = this->nextId();
2090 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002091 if (result != 0) {
2092 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002093 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002094 result = next;
2095 }
2096 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002097 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04002098 }
2099 }
2100 return result;
2101}
2102
Ethan Nicholas0df21132018-07-10 09:37:51 -04002103SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
2104 SpvId rhs, SpvOp_ floatOperator,
2105 SpvOp_ intOperator,
2106 OutputStream& out) {
2107 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
John Stiles9aeed132020-11-24 17:36:06 -05002108 SkASSERT(operandType.isMatrix());
Ethan Nicholas0df21132018-07-10 09:37:51 -04002109 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2110 operandType.rows(),
2111 1));
2112 SpvId columns[4];
2113 for (int i = 0; i < operandType.columns(); i++) {
2114 SpvId columnL = this->nextId();
2115 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2116 SpvId columnR = this->nextId();
2117 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2118 columns[i] = this->nextId();
2119 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2120 }
2121 SpvId result = this->nextId();
2122 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2123 this->writeWord(this->getType(operandType), out);
2124 this->writeWord(result, out);
2125 for (int i = 0; i < operandType.columns(); i++) {
2126 this->writeWord(columns[i], out);
2127 }
2128 return result;
2129}
2130
Ethan Nicholas49465b42019-04-17 12:22:21 -04002131std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2132 if (type.isInteger()) {
2133 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002134 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002135 else if (type.isFloat()) {
2136 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002137 } else {
Ethan Nicholase2c49992020-10-05 11:49:11 -04002138 ABORT("math is unsupported on type '%s'", String(type.name()).c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002139 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002140}
2141
2142SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Token::Kind op,
2143 const Type& rightType, SpvId rhs,
2144 const Type& resultType, OutputStream& out) {
John Stilesd0614f22020-12-09 11:11:41 -05002145 // The comma operator ignores the type of the left-hand side entirely.
2146 if (op == Token::Kind::TK_COMMA) {
2147 return rhs;
2148 }
Ethan Nicholas48e24052018-03-14 13:51:39 -04002149 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002150 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002151 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2152 // handling in SPIR-V
Ethan Nicholas49465b42019-04-17 12:22:21 -04002153 if (this->getActualType(leftType) != this->getActualType(rightType)) {
John Stiles9aeed132020-11-24 17:36:06 -05002154 if (leftType.isVector() && rightType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002155 if (op == Token::Kind::TK_SLASH) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002156 SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
2157 SpvId inverse = this->nextId();
2158 this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
2159 rhs = inverse;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002160 op = Token::Kind::TK_STAR;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002161 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002162 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002163 SpvId result = this->nextId();
2164 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2165 result, lhs, rhs, out);
2166 return result;
2167 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002168 // promote number to vector
2169 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002170 const Type& vecType = leftType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002171 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2172 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002173 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002174 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002175 this->writeWord(rhs, out);
2176 }
2177 rhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002178 operandType = &leftType;
John Stiles9aeed132020-11-24 17:36:06 -05002179 } else if (rightType.isVector() && leftType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002180 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002181 SpvId result = this->nextId();
2182 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2183 result, rhs, lhs, out);
2184 return result;
2185 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002186 // promote number to vector
2187 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002188 const Type& vecType = rightType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002189 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2190 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002191 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002192 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002193 this->writeWord(lhs, out);
2194 }
2195 lhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002196 operandType = &rightType;
John Stiles9aeed132020-11-24 17:36:06 -05002197 } else if (leftType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002198 SpvOp_ spvop;
John Stiles9aeed132020-11-24 17:36:06 -05002199 if (rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002200 spvop = SpvOpMatrixTimesMatrix;
John Stiles9aeed132020-11-24 17:36:06 -05002201 } else if (rightType.isVector()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002202 spvop = SpvOpMatrixTimesVector;
ethannicholasb3058bd2016-07-01 08:22:01 -07002203 } else {
John Stiles9aeed132020-11-24 17:36:06 -05002204 SkASSERT(rightType.isScalar());
Ethan Nicholas49465b42019-04-17 12:22:21 -04002205 spvop = SpvOpMatrixTimesScalar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002206 }
2207 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002208 this->writeInstruction(spvop, this->getType(resultType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002209 return result;
John Stiles9aeed132020-11-24 17:36:06 -05002210 } else if (rightType.isMatrix()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002211 SpvId result = this->nextId();
John Stiles9aeed132020-11-24 17:36:06 -05002212 if (leftType.isVector()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002213 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(resultType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002214 lhs, rhs, out);
2215 } else {
John Stiles9aeed132020-11-24 17:36:06 -05002216 SkASSERT(leftType.isScalar());
Ethan Nicholas49465b42019-04-17 12:22:21 -04002217 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(resultType), result,
2218 rhs, lhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002219 }
2220 return result;
2221 } else {
John Stilesd8ca6b62020-11-23 14:28:36 -05002222 fErrors.error(leftType.fOffset, "unsupported mixed-type expression");
Ethan Nicholas49465b42019-04-17 12:22:21 -04002223 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002224 }
2225 } else {
John Stiles2d4f9592020-10-30 10:29:12 -04002226 operandType = &this->getActualType(leftType);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002227 SkASSERT(*operandType == this->getActualType(rightType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002228 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002229 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002230 case Token::Kind::TK_EQEQ: {
John Stiles9aeed132020-11-24 17:36:06 -05002231 if (operandType->isMatrix()) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002232 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002233 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002234 }
John Stiles4a7dc462020-11-25 11:08:08 -05002235 SkASSERT(resultType.isBoolean());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002236 const Type* tmpType;
John Stiles9aeed132020-11-24 17:36:06 -05002237 if (operandType->isVector()) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002238 tmpType = &fContext.fBool_Type->toCompound(fContext,
2239 operandType->columns(),
2240 operandType->rows());
2241 } else {
2242 tmpType = &resultType;
2243 }
2244 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002245 SpvOpFOrdEqual, SpvOpIEqual,
2246 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002247 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002248 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002249 case Token::Kind::TK_NEQ:
John Stiles9aeed132020-11-24 17:36:06 -05002250 if (operandType->isMatrix()) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002251 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002252 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002253 }
John Stiles4a7dc462020-11-25 11:08:08 -05002254 [[fallthrough]];
2255 case Token::Kind::TK_LOGICALXOR:
2256 SkASSERT(resultType.isBoolean());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002257 const Type* tmpType;
John Stiles9aeed132020-11-24 17:36:06 -05002258 if (operandType->isVector()) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002259 tmpType = &fContext.fBool_Type->toCompound(fContext,
2260 operandType->columns(),
2261 operandType->rows());
2262 } else {
2263 tmpType = &resultType;
2264 }
2265 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002266 SpvOpFOrdNotEqual, SpvOpINotEqual,
2267 SpvOpINotEqual, SpvOpLogicalNotEqual,
2268 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002269 *operandType, SpvOpAny, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002270 case Token::Kind::TK_GT:
John Stiles4a7dc462020-11-25 11:08:08 -05002271 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002272 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2273 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002274 SpvOpUGreaterThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002275 case Token::Kind::TK_LT:
John Stiles4a7dc462020-11-25 11:08:08 -05002276 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002277 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002278 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002279 case Token::Kind::TK_GTEQ:
John Stiles4a7dc462020-11-25 11:08:08 -05002280 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002281 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2282 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002283 SpvOpUGreaterThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002284 case Token::Kind::TK_LTEQ:
John Stiles4a7dc462020-11-25 11:08:08 -05002285 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002286 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2287 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002288 SpvOpULessThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002289 case Token::Kind::TK_PLUS:
John Stiles9aeed132020-11-24 17:36:06 -05002290 if (leftType.isMatrix() && rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002291 SkASSERT(leftType == rightType);
2292 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002293 SpvOpFAdd, SpvOpIAdd, out);
2294 }
Greg Daniel64773e62016-11-22 09:44:03 -05002295 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002296 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002297 case Token::Kind::TK_MINUS:
John Stiles9aeed132020-11-24 17:36:06 -05002298 if (leftType.isMatrix() && rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002299 SkASSERT(leftType == rightType);
2300 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002301 SpvOpFSub, SpvOpISub, out);
2302 }
Greg Daniel64773e62016-11-22 09:44:03 -05002303 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002304 SpvOpISub, SpvOpISub, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002305 case Token::Kind::TK_STAR:
John Stiles9aeed132020-11-24 17:36:06 -05002306 if (leftType.isMatrix() && rightType.isMatrix()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002307 // matrix multiply
2308 SpvId result = this->nextId();
2309 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2310 lhs, rhs, out);
2311 return result;
2312 }
Greg Daniel64773e62016-11-22 09:44:03 -05002313 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002314 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002315 case Token::Kind::TK_SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002316 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002317 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002318 case Token::Kind::TK_PERCENT:
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002319 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2320 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002321 case Token::Kind::TK_SHL:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002322 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2323 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2324 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002325 case Token::Kind::TK_SHR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002326 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2327 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2328 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002329 case Token::Kind::TK_BITWISEAND:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002330 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2331 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002332 case Token::Kind::TK_BITWISEOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002333 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2334 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002335 case Token::Kind::TK_BITWISEXOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002336 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2337 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002338 default:
John Stiles5570c512020-11-19 17:58:07 -05002339 fErrors.error(0, "unsupported token");
Ethan Nicholas49465b42019-04-17 12:22:21 -04002340 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002341 }
2342}
2343
Ethan Nicholas49465b42019-04-17 12:22:21 -04002344SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
John Stiles2d4f9592020-10-30 10:29:12 -04002345 const Expression& left = *b.left();
2346 const Expression& right = *b.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002347 Token::Kind op = b.getOperator();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002348 // handle cases where we don't necessarily evaluate both LHS and RHS
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002349 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002350 case Token::Kind::TK_EQ: {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002351 SpvId rhs = this->writeExpression(right, out);
2352 this->getLValue(left, out)->store(rhs, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002353 return rhs;
2354 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002355 case Token::Kind::TK_LOGICALAND:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002356 return this->writeLogicalAnd(b, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002357 case Token::Kind::TK_LOGICALOR:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002358 return this->writeLogicalOr(b, out);
2359 default:
2360 break;
2361 }
2362
2363 std::unique_ptr<LValue> lvalue;
2364 SpvId lhs;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002365 if (Compiler::IsAssignment(op)) {
2366 lvalue = this->getLValue(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002367 lhs = lvalue->load(out);
2368 } else {
2369 lvalue = nullptr;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002370 lhs = this->writeExpression(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002371 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002372 SpvId rhs = this->writeExpression(right, out);
2373 SpvId result = this->writeBinaryExpression(left.type(), lhs, Compiler::RemoveAssignment(op),
2374 right.type(), rhs, b.type(), out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002375 if (lvalue) {
2376 lvalue->store(result, out);
2377 }
2378 return result;
2379}
2380
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002381SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002382 SkASSERT(a.getOperator() == Token::Kind::TK_LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002383 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002384 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
John Stiles2d4f9592020-10-30 10:29:12 -04002385 SpvId lhs = this->writeExpression(*a.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002386 SpvId rhsLabel = this->nextId();
2387 SpvId end = this->nextId();
2388 SpvId lhsBlock = fCurrentBlock;
2389 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2390 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2391 this->writeLabel(rhsLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04002392 SpvId rhs = this->writeExpression(*a.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002393 SpvId rhsBlock = fCurrentBlock;
2394 this->writeInstruction(SpvOpBranch, end, out);
2395 this->writeLabel(end, out);
2396 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002397 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002398 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002399 return result;
2400}
2401
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002402SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002403 SkASSERT(o.getOperator() == Token::Kind::TK_LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002404 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002405 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
John Stiles2d4f9592020-10-30 10:29:12 -04002406 SpvId lhs = this->writeExpression(*o.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002407 SpvId rhsLabel = this->nextId();
2408 SpvId end = this->nextId();
2409 SpvId lhsBlock = fCurrentBlock;
2410 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2411 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2412 this->writeLabel(rhsLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04002413 SpvId rhs = this->writeExpression(*o.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002414 SpvId rhsBlock = fCurrentBlock;
2415 this->writeInstruction(SpvOpBranch, end, out);
2416 this->writeLabel(end, out);
2417 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002418 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002419 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002420 return result;
2421}
2422
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002423SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002424 const Type& type = t.type();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002425 SpvId test = this->writeExpression(*t.test(), out);
2426 if (t.ifTrue()->type().columns() == 1 &&
2427 t.ifTrue()->isCompileTimeConstant() &&
2428 t.ifFalse()->isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002429 // both true and false are constants, can just use OpSelect
2430 SpvId result = this->nextId();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002431 SpvId trueId = this->writeExpression(*t.ifTrue(), out);
2432 SpvId falseId = this->writeExpression(*t.ifFalse(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002433 this->writeInstruction(SpvOpSelect, this->getType(type), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002434 out);
2435 return result;
2436 }
Greg Daniel64773e62016-11-22 09:44:03 -05002437 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002438 // Adreno. Switched to storing the result in a temp variable as glslang does.
2439 SpvId var = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002440 this->writeInstruction(SpvOpVariable, this->getPointerType(type, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002441 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002442 SpvId trueLabel = this->nextId();
2443 SpvId falseLabel = this->nextId();
2444 SpvId end = this->nextId();
2445 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2446 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2447 this->writeLabel(trueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002448 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifTrue(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002449 this->writeInstruction(SpvOpBranch, end, out);
2450 this->writeLabel(falseLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002451 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifFalse(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002452 this->writeInstruction(SpvOpBranch, end, out);
2453 this->writeLabel(end, out);
2454 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002455 this->writeInstruction(SpvOpLoad, this->getType(type), result, var, out);
2456 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002457 return result;
2458}
2459
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002460SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002461 const Type& type = p.type();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002462 if (p.getOperator() == Token::Kind::TK_MINUS) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002463 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002464 SpvId typeId = this->getType(type);
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002465 SpvId expr = this->writeExpression(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002466 if (is_float(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002467 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002468 } else if (is_signed(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002469 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2470 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002471#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002472 ABORT("unsupported prefix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002473#endif
Brian Salomon23356442018-11-30 15:33:19 -05002474 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002475 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002476 return result;
2477 }
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002478 switch (p.getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002479 case Token::Kind::TK_PLUS:
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002480 return this->writeExpression(*p.operand(), out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002481 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002482 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002483 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
2484 SpvId result = this->writeBinaryOperation(type, type, lv->load(out), one,
Greg Daniel64773e62016-11-22 09:44:03 -05002485 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002486 out);
2487 lv->store(result, out);
2488 return result;
2489 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002490 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002491 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002492 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
2493 SpvId result = this->writeBinaryOperation(type, type, lv->load(out), one, SpvOpFSub,
2494 SpvOpISub, SpvOpISub, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002495 lv->store(result, out);
2496 return result;
2497 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002498 case Token::Kind::TK_LOGICALNOT: {
John Stiles4a7dc462020-11-25 11:08:08 -05002499 SkASSERT(p.operand()->type().isBoolean());
ethannicholasb3058bd2016-07-01 08:22:01 -07002500 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002501 this->writeInstruction(SpvOpLogicalNot, this->getType(type), result,
2502 this->writeExpression(*p.operand(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002503 return result;
2504 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002505 case Token::Kind::TK_BITWISENOT: {
ethannicholas5961bc92016-10-12 06:39:56 -07002506 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002507 this->writeInstruction(SpvOpNot, this->getType(type), result,
2508 this->writeExpression(*p.operand(), out), out);
ethannicholas5961bc92016-10-12 06:39:56 -07002509 return result;
2510 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002511 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002512#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002513 ABORT("unsupported prefix expression: %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002514#endif
2515 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002516 }
2517}
2518
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002519SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002520 const Type& type = p.type();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002521 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002522 SpvId result = lv->load(out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002523 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002524 switch (p.getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002525 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002526 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002527 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2528 lv->store(temp, out);
2529 return result;
2530 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002531 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002532 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002533 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2534 lv->store(temp, out);
2535 return result;
2536 }
2537 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002538#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002539 ABORT("unsupported postfix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002540#endif
2541 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002542 }
2543}
2544
ethannicholasf789b382016-08-03 12:43:36 -07002545SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
Ethan Nicholas59d660c2020-09-28 09:18:15 -04002546 if (b.value()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002547 if (fBoolTrue == 0) {
2548 fBoolTrue = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002549 this->writeInstruction(SpvOpConstantTrue, this->getType(b.type()), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002550 fConstantBuffer);
2551 }
2552 return fBoolTrue;
2553 } else {
2554 if (fBoolFalse == 0) {
2555 fBoolFalse = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002556 this->writeInstruction(SpvOpConstantFalse, this->getType(b.type()), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002557 fConstantBuffer);
2558 }
2559 return fBoolFalse;
2560 }
2561}
2562
ethannicholasf789b382016-08-03 12:43:36 -07002563SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002564 const Type& type = i.type();
2565 ConstantType constantType;
John Stilesfd41d872020-11-25 22:39:45 -05002566 if (type == *fContext.fInt_Type || type.typeKind() == Type::TypeKind::kEnum) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002567 constantType = ConstantType::kInt;
2568 } else if (type == *fContext.fUInt_Type) {
2569 constantType = ConstantType::kUInt;
2570 } else if (type == *fContext.fShort_Type || type == *fContext.fByte_Type) {
2571 constantType = ConstantType::kShort;
2572 } else if (type == *fContext.fUShort_Type || type == *fContext.fUByte_Type) {
2573 constantType = ConstantType::kUShort;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002574 } else {
2575 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002576 }
Ethan Nicholase96cdd12020-09-28 16:27:18 -04002577 std::pair<ConstantValue, ConstantType> key(i.value(), constantType);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002578 auto entry = fNumberConstants.find(key);
2579 if (entry == fNumberConstants.end()) {
2580 SpvId result = this->nextId();
Ethan Nicholase96cdd12020-09-28 16:27:18 -04002581 this->writeInstruction(SpvOpConstant, this->getType(type), result, (SpvId) i.value(),
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002582 fConstantBuffer);
2583 fNumberConstants[key] = result;
2584 return result;
2585 }
2586 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002587}
2588
ethannicholasf789b382016-08-03 12:43:36 -07002589SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002590 const Type& type = f.type();
2591 ConstantType constantType;
2592 if (type == *fContext.fHalf_Type) {
2593 constantType = ConstantType::kHalf;
ethannicholasb3058bd2016-07-01 08:22:01 -07002594 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002595 constantType = ConstantType::kFloat;
ethannicholasb3058bd2016-07-01 08:22:01 -07002596 }
Ethan Nicholasa3f22f12020-10-01 12:13:17 -04002597 float value = (float) f.value();
2598 std::pair<ConstantValue, ConstantType> key(f.value(), constantType);
John Stiles8c578662020-06-01 15:32:47 +00002599 auto entry = fNumberConstants.find(key);
2600 if (entry == fNumberConstants.end()) {
2601 SpvId result = this->nextId();
2602 uint32_t bits;
2603 SkASSERT(sizeof(bits) == sizeof(value));
2604 memcpy(&bits, &value, sizeof(bits));
Ethan Nicholas30d30222020-09-11 12:27:26 -04002605 this->writeInstruction(SpvOpConstant, this->getType(type), result, bits,
John Stiles8c578662020-06-01 15:32:47 +00002606 fConstantBuffer);
2607 fNumberConstants[key] = result;
2608 return result;
2609 }
2610 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002611}
2612
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002613SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002614 SpvId result = fFunctionMap[&f];
Ethan Nicholased84b732020-10-08 11:45:44 -04002615 this->writeInstruction(SpvOpFunction, this->getType(f.returnType()), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002616 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04002617 this->writeInstruction(SpvOpName, result, f.name(), fNameBuffer);
Brian Osman5bf3e202020-10-13 10:34:18 -04002618 const std::vector<const Variable*>& parameters = f.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -04002619 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002620 SpvId id = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -04002621 fVariableMap[parameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002622 SpvId type;
Ethan Nicholased84b732020-10-08 11:45:44 -04002623 type = this->getPointerType(parameters[i]->type(), SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002624 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2625 }
2626 return result;
2627}
2628
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002629SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2630 fVariableBuffer.reset();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002631 SpvId result = this->writeFunctionStart(f.declaration(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002632 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002633 StringStream bodyBuffer;
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002634 this->writeBlock((Block&) *f.body(), bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002635 write_stringstream(fVariableBuffer, out);
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002636 if (f.declaration().name() == "main") {
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002637 write_stringstream(fGlobalInitializersBuffer, out);
2638 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002639 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002640 if (fCurrentBlock) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002641 if (f.declaration().returnType() == *fContext.fVoid_Type) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002642 this->writeInstruction(SpvOpReturn, out);
2643 } else {
2644 this->writeInstruction(SpvOpUnreachable, out);
2645 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002646 }
2647 this->writeInstruction(SpvOpFunctionEnd, out);
2648 return result;
2649}
2650
2651void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2652 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002653 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002654 fDecorationBuffer);
2655 }
2656 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002657 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002658 fDecorationBuffer);
2659 }
2660 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002661 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002662 fDecorationBuffer);
2663 }
2664 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002665 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002666 fDecorationBuffer);
2667 }
Greg Daniel64773e62016-11-22 09:44:03 -05002668 if (layout.fInputAttachmentIndex >= 0) {
2669 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2670 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002671 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002672 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002673 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002674 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002675 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002676 fDecorationBuffer);
2677 }
2678}
2679
2680void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2681 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002682 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002683 layout.fLocation, fDecorationBuffer);
2684 }
2685 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002686 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002687 layout.fBinding, fDecorationBuffer);
2688 }
2689 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002690 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002691 layout.fIndex, fDecorationBuffer);
2692 }
2693 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002694 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002695 layout.fSet, fDecorationBuffer);
2696 }
Greg Daniel64773e62016-11-22 09:44:03 -05002697 if (layout.fInputAttachmentIndex >= 0) {
2698 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2699 layout.fInputAttachmentIndex, fDecorationBuffer);
2700 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002701 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002702 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002703 layout.fBuiltin, fDecorationBuffer);
2704 }
2705}
2706
Ethan Nicholas81d15112018-07-13 12:48:50 -04002707static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2708 switch (m.fLayout.fPrimitive) {
2709 case Layout::kPoints_Primitive:
2710 *outSkInCount = 1;
2711 break;
2712 case Layout::kLines_Primitive:
2713 *outSkInCount = 2;
2714 break;
2715 case Layout::kLinesAdjacency_Primitive:
2716 *outSkInCount = 4;
2717 break;
2718 case Layout::kTriangles_Primitive:
2719 *outSkInCount = 3;
2720 break;
2721 case Layout::kTrianglesAdjacency_Primitive:
2722 *outSkInCount = 6;
2723 break;
2724 default:
2725 return;
2726 }
2727}
2728
Stephen White88574972020-06-23 19:09:29 -04002729SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf, bool appendRTHeight) {
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002730 bool isBuffer = ((intf.variable().modifiers().fFlags & Modifiers::kBuffer_Flag) != 0);
2731 bool pushConstant = ((intf.variable().modifiers().fLayout.fFlags &
2732 Layout::kPushConstant_Flag) != 0);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002733 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2734 MemoryLayout(MemoryLayout::k430_Standard) :
2735 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002736 SpvId result = this->nextId();
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002737 const Type* type = &intf.variable().type();
John Stiles21f5f452020-11-30 09:57:59 -05002738 if (!MemoryLayout::LayoutIsSupported(*type)) {
John Stiles0023c0c2020-11-16 13:32:18 -05002739 fErrors.error(type->fOffset, "type '" + type->name() + "' is not permitted here");
2740 return this->nextId();
2741 }
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002742 Modifiers intfModifiers = intf.variable().modifiers();
2743 SpvStorageClass_ storageClass = get_storage_class(intfModifiers);
Stephen White88574972020-06-23 19:09:29 -04002744 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Greg Daniele6ab9982018-08-22 13:56:32 +00002745 SkASSERT(fRTHeightStructId == (SpvId) -1);
2746 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002747 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002748 fRTHeightStructId = result;
2749 fRTHeightFieldIndex = fields.size();
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002750 fRTHeightStorageClass = storageClass;
Greg Daniele6ab9982018-08-22 13:56:32 +00002751 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002752 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002753 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002754 SpvId typeId;
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002755 if (intfModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osman133724c2020-10-28 14:14:39 -04002756 for (const ProgramElement* e : fProgram.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04002757 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04002758 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholas81d15112018-07-13 12:48:50 -04002759 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002760 }
2761 }
Ethan Nicholase6592142020-09-08 10:22:09 -04002762 typeId = this->getType(Type("sk_in", Type::TypeKind::kArray,
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002763 intf.variable().type().componentType(),
Ethan Nicholase6592142020-09-08 10:22:09 -04002764 fSkInCount),
2765 memoryLayout);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002766 } else {
2767 typeId = this->getType(*type, memoryLayout);
2768 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002769 if (intfModifiers.fFlags & Modifiers::kBuffer_Flag) {
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002770 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002771 } else if (intfModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002772 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002773 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002774 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002775 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002776 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002777 Layout layout = intfModifiers.fLayout;
2778 if (intfModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002779 layout.fSet = 0;
2780 }
2781 this->writeLayout(layout, result);
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002782 fVariableMap[&intf.variable()] = result;
Stephen White88574972020-06-23 19:09:29 -04002783 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002784 delete type;
2785 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002786 return result;
2787}
2788
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002789void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002790 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2791}
2792
2793void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2794 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002795 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2796 }
2797}
2798
Brian Osman010ce6a2020-10-19 16:34:10 -04002799bool is_dead(const Variable& var, const ProgramUsage* usage) {
2800 ProgramUsage::VariableCounts counts = usage->get(var);
2801 if (counts.fRead || counts.fWrite) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002802 return false;
2803 }
2804 // not entirely sure what the rules are for when it's safe to elide interface variables, but it
2805 // causes various problems to elide some of them even when dead. But it also causes problems
2806 // *not* to elide sk_SampleMask when it's not being used.
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002807 if (!(var.modifiers().fFlags & (Modifiers::kIn_Flag |
2808 Modifiers::kOut_Flag |
2809 Modifiers::kUniform_Flag |
2810 Modifiers::kBuffer_Flag))) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002811 return true;
2812 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002813 return var.modifiers().fLayout.fBuiltin == SK_SAMPLEMASK_BUILTIN;
Chris Dalton2284aab2019-11-15 11:02:24 -07002814}
2815
ethannicholas5961bc92016-10-12 06:39:56 -07002816#define BUILTIN_IGNORE 9999
Brian Osmanc0213602020-10-06 14:43:32 -04002817void SPIRVCodeGenerator::writeGlobalVar(Program::Kind kind, const VarDeclaration& varDecl,
2818 OutputStream& out) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002819 const Variable& var = varDecl.var();
Brian Osmanc0213602020-10-06 14:43:32 -04002820 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2821 // in the OpenGL backend.
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002822 SkASSERT(!(var.modifiers().fFlags & (Modifiers::kReadOnly_Flag |
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002823 Modifiers::kWriteOnly_Flag |
2824 Modifiers::kCoherent_Flag |
2825 Modifiers::kVolatile_Flag |
2826 Modifiers::kRestrict_Flag)));
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002827 if (var.modifiers().fLayout.fBuiltin == BUILTIN_IGNORE) {
Brian Osmanc0213602020-10-06 14:43:32 -04002828 return;
2829 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002830 if (var.modifiers().fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
Brian Osmanc0213602020-10-06 14:43:32 -04002831 kind != Program::kFragment_Kind) {
2832 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
2833 return;
2834 }
Brian Osman010ce6a2020-10-19 16:34:10 -04002835 if (is_dead(var, fProgram.fUsage.get())) {
Brian Osmanc0213602020-10-06 14:43:32 -04002836 return;
2837 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002838 const Type& type = var.type();
Brian Osmanc0213602020-10-06 14:43:32 -04002839 SpvStorageClass_ storageClass;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002840 if (var.modifiers().fFlags & Modifiers::kIn_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002841 storageClass = SpvStorageClassInput;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002842 } else if (var.modifiers().fFlags & Modifiers::kOut_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002843 storageClass = SpvStorageClassOutput;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002844 } else if (var.modifiers().fFlags & Modifiers::kUniform_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002845 if (type.typeKind() == Type::TypeKind::kSampler ||
2846 type.typeKind() == Type::TypeKind::kSeparateSampler ||
2847 type.typeKind() == Type::TypeKind::kTexture) {
2848 storageClass = SpvStorageClassUniformConstant;
ethannicholasb3058bd2016-07-01 08:22:01 -07002849 } else {
Brian Osmanc0213602020-10-06 14:43:32 -04002850 storageClass = SpvStorageClassUniform;
ethannicholasb3058bd2016-07-01 08:22:01 -07002851 }
Brian Osmanc0213602020-10-06 14:43:32 -04002852 } else {
2853 storageClass = SpvStorageClassPrivate;
2854 }
2855 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002856 fVariableMap[&var] = id;
Brian Osmanc0213602020-10-06 14:43:32 -04002857 SpvId typeId;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002858 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osmanc0213602020-10-06 14:43:32 -04002859 typeId = this->getPointerType(
2860 Type("sk_in", Type::TypeKind::kArray, type.componentType(), fSkInCount),
2861 storageClass);
2862 } else {
2863 typeId = this->getPointerType(type, storageClass);
2864 }
2865 this->writeInstruction(SpvOpVariable, typeId, id, storageClass, fConstantBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002866 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002867 this->writePrecisionModifier(type, id);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002868 if (varDecl.value()) {
Brian Osmanc0213602020-10-06 14:43:32 -04002869 SkASSERT(!fCurrentBlock);
2870 fCurrentBlock = -1;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002871 SpvId value = this->writeExpression(*varDecl.value(), fGlobalInitializersBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002872 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
2873 fCurrentBlock = 0;
2874 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002875 this->writeLayout(var.modifiers().fLayout, id);
2876 if (var.modifiers().fFlags & Modifiers::kFlat_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002877 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2878 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002879 if (var.modifiers().fFlags & Modifiers::kNoPerspective_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002880 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2881 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002882 }
2883}
2884
Brian Osmanc0213602020-10-06 14:43:32 -04002885void SPIRVCodeGenerator::writeVarDeclaration(const VarDeclaration& varDecl, OutputStream& out) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002886 const Variable& var = varDecl.var();
Brian Osmanc0213602020-10-06 14:43:32 -04002887 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2888 // in the OpenGL backend.
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002889 SkASSERT(!(var.modifiers().fFlags & (Modifiers::kReadOnly_Flag |
2890 Modifiers::kWriteOnly_Flag |
2891 Modifiers::kCoherent_Flag |
2892 Modifiers::kVolatile_Flag |
2893 Modifiers::kRestrict_Flag)));
Brian Osmanc0213602020-10-06 14:43:32 -04002894 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002895 fVariableMap[&var] = id;
2896 SpvId type = this->getPointerType(var.type(), SpvStorageClassFunction);
Brian Osmanc0213602020-10-06 14:43:32 -04002897 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002898 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
2899 if (varDecl.value()) {
2900 SpvId value = this->writeExpression(*varDecl.value(), out);
Brian Osmanc0213602020-10-06 14:43:32 -04002901 this->writeInstruction(SpvOpStore, id, value, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002902 }
2903}
2904
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002905void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002906 switch (s.kind()) {
John Stiles98c1f822020-09-09 14:18:53 -04002907 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04002908 case Statement::Kind::kNop:
Ethan Nicholascb670962017-04-20 19:31:52 -04002909 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002910 case Statement::Kind::kBlock:
ethannicholasb3058bd2016-07-01 08:22:01 -07002911 this->writeBlock((Block&) s, out);
2912 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002913 case Statement::Kind::kExpression:
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04002914 this->writeExpression(*s.as<ExpressionStatement>().expression(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002915 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002916 case Statement::Kind::kReturn:
John Stiles26f98502020-08-18 09:30:51 -04002917 this->writeReturnStatement(s.as<ReturnStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002918 break;
Brian Osmanc0213602020-10-06 14:43:32 -04002919 case Statement::Kind::kVarDeclaration:
2920 this->writeVarDeclaration(s.as<VarDeclaration>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002921 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002922 case Statement::Kind::kIf:
John Stiles26f98502020-08-18 09:30:51 -04002923 this->writeIfStatement(s.as<IfStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002924 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002925 case Statement::Kind::kFor:
John Stiles26f98502020-08-18 09:30:51 -04002926 this->writeForStatement(s.as<ForStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002927 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002928 case Statement::Kind::kWhile:
John Stiles26f98502020-08-18 09:30:51 -04002929 this->writeWhileStatement(s.as<WhileStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002930 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002931 case Statement::Kind::kDo:
John Stiles26f98502020-08-18 09:30:51 -04002932 this->writeDoStatement(s.as<DoStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002933 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002934 case Statement::Kind::kSwitch:
John Stiles26f98502020-08-18 09:30:51 -04002935 this->writeSwitchStatement(s.as<SwitchStatement>(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002936 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002937 case Statement::Kind::kBreak:
ethannicholasb3058bd2016-07-01 08:22:01 -07002938 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2939 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002940 case Statement::Kind::kContinue:
ethannicholasb3058bd2016-07-01 08:22:01 -07002941 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2942 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002943 case Statement::Kind::kDiscard:
ethannicholasb3058bd2016-07-01 08:22:01 -07002944 this->writeInstruction(SpvOpKill, out);
2945 break;
2946 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002947#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002948 ABORT("unsupported statement: %s", s.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002949#endif
2950 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002951 }
2952}
2953
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002954void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04002955 for (const std::unique_ptr<Statement>& stmt : b.children()) {
2956 this->writeStatement(*stmt, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002957 }
2958}
2959
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002960void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002961 SpvId test = this->writeExpression(*stmt.test(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002962 SpvId ifTrue = this->nextId();
2963 SpvId ifFalse = this->nextId();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002964 if (stmt.ifFalse()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002965 SpvId end = this->nextId();
2966 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2967 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2968 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002969 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002970 if (fCurrentBlock) {
2971 this->writeInstruction(SpvOpBranch, end, out);
2972 }
2973 this->writeLabel(ifFalse, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002974 this->writeStatement(*stmt.ifFalse(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002975 if (fCurrentBlock) {
2976 this->writeInstruction(SpvOpBranch, end, out);
2977 }
2978 this->writeLabel(end, out);
2979 } else {
2980 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2981 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2982 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002983 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002984 if (fCurrentBlock) {
2985 this->writeInstruction(SpvOpBranch, ifFalse, out);
2986 }
2987 this->writeLabel(ifFalse, out);
2988 }
2989}
2990
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002991void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04002992 if (f.initializer()) {
2993 this->writeStatement(*f.initializer(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002994 }
2995 SpvId header = this->nextId();
2996 SpvId start = this->nextId();
2997 SpvId body = this->nextId();
2998 SpvId next = this->nextId();
2999 fContinueTarget.push(next);
3000 SpvId end = this->nextId();
3001 fBreakTarget.push(end);
3002 this->writeInstruction(SpvOpBranch, header, out);
3003 this->writeLabel(header, out);
3004 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07003005 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003006 this->writeLabel(start, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003007 if (f.test()) {
3008 SpvId test = this->writeExpression(*f.test(), out);
ethannicholas22f939e2016-10-13 13:25:34 -07003009 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
3010 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003011 this->writeLabel(body, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003012 this->writeStatement(*f.statement(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003013 if (fCurrentBlock) {
3014 this->writeInstruction(SpvOpBranch, next, out);
3015 }
3016 this->writeLabel(next, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003017 if (f.next()) {
3018 this->writeExpression(*f.next(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003019 }
3020 this->writeInstruction(SpvOpBranch, header, out);
3021 this->writeLabel(end, out);
3022 fBreakTarget.pop();
3023 fContinueTarget.pop();
3024}
3025
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003026void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003027 SpvId header = this->nextId();
3028 SpvId start = this->nextId();
3029 SpvId body = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003030 SpvId continueTarget = this->nextId();
3031 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003032 SpvId end = this->nextId();
3033 fBreakTarget.push(end);
3034 this->writeInstruction(SpvOpBranch, header, out);
3035 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003036 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003037 this->writeInstruction(SpvOpBranch, start, out);
3038 this->writeLabel(start, out);
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003039 SpvId test = this->writeExpression(*w.test(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003040 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
3041 this->writeLabel(body, out);
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003042 this->writeStatement(*w.statement(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003043 if (fCurrentBlock) {
Ethan Nicholas0d997662019-04-08 09:46:01 -04003044 this->writeInstruction(SpvOpBranch, continueTarget, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003045 }
Ethan Nicholas0d997662019-04-08 09:46:01 -04003046 this->writeLabel(continueTarget, out);
3047 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003048 this->writeLabel(end, out);
3049 fBreakTarget.pop();
3050 fContinueTarget.pop();
3051}
3052
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003053void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003054 SpvId header = this->nextId();
3055 SpvId start = this->nextId();
3056 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003057 SpvId continueTarget = this->nextId();
3058 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003059 SpvId end = this->nextId();
3060 fBreakTarget.push(end);
3061 this->writeInstruction(SpvOpBranch, header, out);
3062 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003063 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003064 this->writeInstruction(SpvOpBranch, start, out);
3065 this->writeLabel(start, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003066 this->writeStatement(*d.statement(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003067 if (fCurrentBlock) {
3068 this->writeInstruction(SpvOpBranch, next, out);
3069 }
3070 this->writeLabel(next, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003071 SpvId test = this->writeExpression(*d.test(), out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003072 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
3073 this->writeLabel(continueTarget, out);
3074 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003075 this->writeLabel(end, out);
3076 fBreakTarget.pop();
3077 fContinueTarget.pop();
3078}
3079
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003080void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04003081 SpvId value = this->writeExpression(*s.value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003082 std::vector<SpvId> labels;
3083 SpvId end = this->nextId();
3084 SpvId defaultLabel = end;
3085 fBreakTarget.push(end);
3086 int size = 3;
John Stiles2d4f9592020-10-30 10:29:12 -04003087 auto& cases = s.cases();
3088 for (const std::unique_ptr<SwitchCase>& c : cases) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003089 SpvId label = this->nextId();
3090 labels.push_back(label);
John Stiles2d4f9592020-10-30 10:29:12 -04003091 if (c->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003092 size += 2;
3093 } else {
3094 defaultLabel = label;
3095 }
3096 }
3097 labels.push_back(end);
3098 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3099 this->writeOpCode(SpvOpSwitch, size, out);
3100 this->writeWord(value, out);
3101 this->writeWord(defaultLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04003102 for (size_t i = 0; i < cases.size(); ++i) {
3103 if (!cases[i]->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003104 continue;
3105 }
John Stiles2d4f9592020-10-30 10:29:12 -04003106 this->writeWord(cases[i]->value()->as<IntLiteral>().value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003107 this->writeWord(labels[i], out);
3108 }
John Stiles2d4f9592020-10-30 10:29:12 -04003109 for (size_t i = 0; i < cases.size(); ++i) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003110 this->writeLabel(labels[i], out);
John Stiles2d4f9592020-10-30 10:29:12 -04003111 for (const auto& stmt : cases[i]->statements()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003112 this->writeStatement(*stmt, out);
3113 }
3114 if (fCurrentBlock) {
3115 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3116 }
3117 }
3118 this->writeLabel(end, out);
3119 fBreakTarget.pop();
3120}
3121
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003122void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003123 if (r.expression()) {
3124 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.expression(), out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003125 out);
3126 } else {
3127 this->writeInstruction(SpvOpReturn, out);
3128 }
3129}
3130
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003131void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003132 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003133 int invocations = 1;
Brian Osman133724c2020-10-28 14:14:39 -04003134 for (const ProgramElement* e : fProgram.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003135 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04003136 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003137 if (m.fFlags & Modifiers::kIn_Flag) {
3138 if (m.fLayout.fInvocations != -1) {
3139 invocations = m.fLayout.fInvocations;
3140 }
3141 SpvId input;
3142 switch (m.fLayout.fPrimitive) {
3143 case Layout::kPoints_Primitive:
3144 input = SpvExecutionModeInputPoints;
3145 break;
3146 case Layout::kLines_Primitive:
3147 input = SpvExecutionModeInputLines;
3148 break;
3149 case Layout::kLinesAdjacency_Primitive:
3150 input = SpvExecutionModeInputLinesAdjacency;
3151 break;
3152 case Layout::kTriangles_Primitive:
3153 input = SpvExecutionModeTriangles;
3154 break;
3155 case Layout::kTrianglesAdjacency_Primitive:
3156 input = SpvExecutionModeInputTrianglesAdjacency;
3157 break;
3158 default:
3159 input = 0;
3160 break;
3161 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003162 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003163 if (input) {
3164 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3165 }
3166 } else if (m.fFlags & Modifiers::kOut_Flag) {
3167 SpvId output;
3168 switch (m.fLayout.fPrimitive) {
3169 case Layout::kPoints_Primitive:
3170 output = SpvExecutionModeOutputPoints;
3171 break;
3172 case Layout::kLineStrip_Primitive:
3173 output = SpvExecutionModeOutputLineStrip;
3174 break;
3175 case Layout::kTriangleStrip_Primitive:
3176 output = SpvExecutionModeOutputTriangleStrip;
3177 break;
3178 default:
3179 output = 0;
3180 break;
3181 }
3182 if (output) {
3183 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3184 }
3185 if (m.fLayout.fMaxVertices != -1) {
3186 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3187 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3188 out);
3189 }
3190 }
3191 }
3192 }
3193 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3194 invocations, out);
3195}
3196
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003197void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003198 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003199 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003200 std::set<SpvId> interfaceVars;
Brian Osman1f8f5752020-10-28 14:46:21 -04003201 // assign IDs to functions
Brian Osman133724c2020-10-28 14:14:39 -04003202 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003203 switch (e->kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04003204 case ProgramElement::Kind::kFunction: {
Brian Osman1179fcf2020-10-08 16:04:40 -04003205 const FunctionDefinition& f = e->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04003206 fFunctionMap[&f.declaration()] = this->nextId();
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003207 break;
3208 }
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003209 default:
3210 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003211 }
3212 }
Brian Osman133724c2020-10-28 14:14:39 -04003213 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003214 if (e->is<InterfaceBlock>()) {
Brian Osman1f8f5752020-10-28 14:46:21 -04003215 const InterfaceBlock& intf = e->as<InterfaceBlock>();
ethannicholasb3058bd2016-07-01 08:22:01 -07003216 SpvId id = this->writeInterfaceBlock(intf);
Brian Osman1f8f5752020-10-28 14:46:21 -04003217
3218 const Modifiers& modifiers = intf.variable().modifiers();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003219 if (((modifiers.fFlags & Modifiers::kIn_Flag) ||
3220 (modifiers.fFlags & Modifiers::kOut_Flag)) &&
3221 modifiers.fLayout.fBuiltin == -1 &&
Brian Osman010ce6a2020-10-19 16:34:10 -04003222 !is_dead(intf.variable(), fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003223 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003224 }
3225 }
3226 }
Brian Osman133724c2020-10-28 14:14:39 -04003227 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003228 if (e->is<GlobalVarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04003229 this->writeGlobalVar(program.fKind,
3230 e->as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>(),
3231 body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003232 }
3233 }
Brian Osman133724c2020-10-28 14:14:39 -04003234 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003235 if (e->is<FunctionDefinition>()) {
3236 this->writeFunction(e->as<FunctionDefinition>(), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003237 }
3238 }
ethannicholasd598f792016-07-25 10:08:54 -07003239 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003240 for (auto entry : fFunctionMap) {
Ethan Nicholase2c49992020-10-05 11:49:11 -04003241 if (entry.first->name() == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003242 main = entry.first;
3243 }
3244 }
Ethan Nicholas1a668d22019-04-18 10:37:40 -04003245 if (!main) {
3246 fErrors.error(0, "program does not contain a main() function");
3247 return;
3248 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003249 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003250 const Variable* var = entry.first;
Ethan Nicholas453f67f2020-10-09 10:43:45 -04003251 if (var->storage() == Variable::Storage::kGlobal &&
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003252 ((var->modifiers().fFlags & Modifiers::kIn_Flag) ||
Brian Osman010ce6a2020-10-19 16:34:10 -04003253 (var->modifiers().fFlags & Modifiers::kOut_Flag)) &&
3254 !is_dead(*var, fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003255 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003256 }
3257 }
3258 this->writeCapabilities(out);
3259 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3260 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003261 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->name().fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003262 (int32_t) interfaceVars.size(), out);
3263 switch (program.fKind) {
3264 case Program::kVertex_Kind:
3265 this->writeWord(SpvExecutionModelVertex, out);
3266 break;
3267 case Program::kFragment_Kind:
3268 this->writeWord(SpvExecutionModelFragment, out);
3269 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003270 case Program::kGeometry_Kind:
3271 this->writeWord(SpvExecutionModelGeometry, out);
3272 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003273 default:
3274 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003275 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003276 SpvId entryPoint = fFunctionMap[main];
3277 this->writeWord(entryPoint, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003278 this->writeString(main->name().fChars, main->name().fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003279 for (int var : interfaceVars) {
3280 this->writeWord(var, out);
3281 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003282 if (program.fKind == Program::kGeometry_Kind) {
3283 this->writeGeometryShaderExecutionMode(entryPoint, out);
3284 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003285 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003286 this->writeInstruction(SpvOpExecutionMode,
3287 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003288 SpvExecutionModeOriginUpperLeft,
3289 out);
3290 }
Brian Osman133724c2020-10-28 14:14:39 -04003291 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003292 if (e->is<Extension>()) {
3293 this->writeInstruction(SpvOpSourceExtension, e->as<Extension>().name().c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003294 }
3295 }
Greg Daniel64773e62016-11-22 09:44:03 -05003296
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003297 write_stringstream(fExtraGlobalsBuffer, out);
3298 write_stringstream(fNameBuffer, out);
3299 write_stringstream(fDecorationBuffer, out);
3300 write_stringstream(fConstantBuffer, out);
3301 write_stringstream(fExternalFunctionsBuffer, out);
3302 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003303}
3304
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003305bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003306 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003307 this->writeWord(SpvMagicNumber, *fOut);
3308 this->writeWord(SpvVersion, *fOut);
3309 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003310 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003311 this->writeInstructions(fProgram, buffer);
3312 this->writeWord(fIdCount, *fOut);
3313 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003314 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003315 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003316}
3317
John Stilesa6841be2020-08-06 14:11:56 -04003318} // namespace SkSL