blob: f39b23b54b109f09365d52e0ab3ba3862007912d [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Ethan Nicholasbcf35f82017-03-30 18:42:48 +00007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Ethan Nicholas9bd301d2017-03-31 16:04:34 +00009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "src/sksl/GLSL.std.450.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070011
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "src/sksl/SkSLCompiler.h"
13#include "src/sksl/ir/SkSLExpressionStatement.h"
14#include "src/sksl/ir/SkSLExtension.h"
15#include "src/sksl/ir/SkSLIndexExpression.h"
16#include "src/sksl/ir/SkSLVariableReference.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070017
Ethan Nicholas0be34802019-08-15 12:36:58 -040018#ifdef SK_VULKAN
19#include "src/gpu/vk/GrVkCaps.h"
20#endif
21
ethannicholasb3058bd2016-07-01 08:22:01 -070022namespace SkSL {
23
ethannicholasb3058bd2016-07-01 08:22:01 -070024static const int32_t SKSL_MAGIC = 0x0; // FIXME: we should probably register a magic number
25
26void SPIRVCodeGenerator::setupIntrinsics() {
27#define ALL_GLSL(x) std::make_tuple(kGLSL_STD_450_IntrinsicKind, GLSLstd450 ## x, GLSLstd450 ## x, \
28 GLSLstd450 ## x, GLSLstd450 ## x)
29#define BY_TYPE_GLSL(ifFloat, ifInt, ifUInt) std::make_tuple(kGLSL_STD_450_IntrinsicKind, \
30 GLSLstd450 ## ifFloat, \
31 GLSLstd450 ## ifInt, \
32 GLSLstd450 ## ifUInt, \
33 SpvOpUndef)
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040034#define ALL_SPIRV(x) std::make_tuple(kSPIRV_IntrinsicKind, SpvOp ## x, SpvOp ## x, SpvOp ## x, \
35 SpvOp ## x)
ethannicholasb3058bd2016-07-01 08:22:01 -070036#define SPECIAL(x) std::make_tuple(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic, \
37 k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
38 k ## x ## _SpecialIntrinsic)
Ethan Nicholas0df1b042017-03-31 13:56:23 -040039 fIntrinsicMap[String("round")] = ALL_GLSL(Round);
40 fIntrinsicMap[String("roundEven")] = ALL_GLSL(RoundEven);
41 fIntrinsicMap[String("trunc")] = ALL_GLSL(Trunc);
42 fIntrinsicMap[String("abs")] = BY_TYPE_GLSL(FAbs, SAbs, SAbs);
43 fIntrinsicMap[String("sign")] = BY_TYPE_GLSL(FSign, SSign, SSign);
44 fIntrinsicMap[String("floor")] = ALL_GLSL(Floor);
45 fIntrinsicMap[String("ceil")] = ALL_GLSL(Ceil);
46 fIntrinsicMap[String("fract")] = ALL_GLSL(Fract);
47 fIntrinsicMap[String("radians")] = ALL_GLSL(Radians);
48 fIntrinsicMap[String("degrees")] = ALL_GLSL(Degrees);
49 fIntrinsicMap[String("sin")] = ALL_GLSL(Sin);
50 fIntrinsicMap[String("cos")] = ALL_GLSL(Cos);
51 fIntrinsicMap[String("tan")] = ALL_GLSL(Tan);
52 fIntrinsicMap[String("asin")] = ALL_GLSL(Asin);
53 fIntrinsicMap[String("acos")] = ALL_GLSL(Acos);
54 fIntrinsicMap[String("atan")] = SPECIAL(Atan);
55 fIntrinsicMap[String("sinh")] = ALL_GLSL(Sinh);
56 fIntrinsicMap[String("cosh")] = ALL_GLSL(Cosh);
57 fIntrinsicMap[String("tanh")] = ALL_GLSL(Tanh);
58 fIntrinsicMap[String("asinh")] = ALL_GLSL(Asinh);
59 fIntrinsicMap[String("acosh")] = ALL_GLSL(Acosh);
60 fIntrinsicMap[String("atanh")] = ALL_GLSL(Atanh);
61 fIntrinsicMap[String("pow")] = ALL_GLSL(Pow);
62 fIntrinsicMap[String("exp")] = ALL_GLSL(Exp);
63 fIntrinsicMap[String("log")] = ALL_GLSL(Log);
64 fIntrinsicMap[String("exp2")] = ALL_GLSL(Exp2);
65 fIntrinsicMap[String("log2")] = ALL_GLSL(Log2);
66 fIntrinsicMap[String("sqrt")] = ALL_GLSL(Sqrt);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040067 fIntrinsicMap[String("inverse")] = ALL_GLSL(MatrixInverse);
John Stilesa07338f2020-12-17 12:39:08 -050068 fIntrinsicMap[String("outerProduct")] = ALL_SPIRV(OuterProduct);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040069 fIntrinsicMap[String("transpose")] = ALL_SPIRV(Transpose);
John Stiles3679cd12020-12-09 16:22:12 -050070 fIntrinsicMap[String("isinf")] = ALL_SPIRV(IsInf);
71 fIntrinsicMap[String("isnan")] = ALL_SPIRV(IsNan);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040072 fIntrinsicMap[String("inversesqrt")] = ALL_GLSL(InverseSqrt);
73 fIntrinsicMap[String("determinant")] = ALL_GLSL(Determinant);
74 fIntrinsicMap[String("matrixInverse")] = ALL_GLSL(MatrixInverse);
Ethan Nicholas70a44b22017-11-30 09:09:16 -050075 fIntrinsicMap[String("mod")] = SPECIAL(Mod);
John Stiles01957272020-12-09 17:14:47 -050076 fIntrinsicMap[String("modf")] = ALL_GLSL(Modf);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050077 fIntrinsicMap[String("min")] = SPECIAL(Min);
78 fIntrinsicMap[String("max")] = SPECIAL(Max);
79 fIntrinsicMap[String("clamp")] = SPECIAL(Clamp);
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040080 fIntrinsicMap[String("saturate")] = SPECIAL(Saturate);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040081 fIntrinsicMap[String("dot")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
Ethan Nicholas0187ae62017-05-03 11:03:44 -040082 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050083 fIntrinsicMap[String("mix")] = SPECIAL(Mix);
Brian Osman6ba3be12020-11-13 16:32:52 -050084 fIntrinsicMap[String("step")] = SPECIAL(Step);
85 fIntrinsicMap[String("smoothstep")] = SPECIAL(SmoothStep);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040086 fIntrinsicMap[String("fma")] = ALL_GLSL(Fma);
87 fIntrinsicMap[String("frexp")] = ALL_GLSL(Frexp);
88 fIntrinsicMap[String("ldexp")] = ALL_GLSL(Ldexp);
ethannicholasb3058bd2016-07-01 08:22:01 -070089
Ethan Nicholas0df1b042017-03-31 13:56:23 -040090#define PACK(type) fIntrinsicMap[String("pack" #type)] = ALL_GLSL(Pack ## type); \
91 fIntrinsicMap[String("unpack" #type)] = ALL_GLSL(Unpack ## type)
ethannicholasb3058bd2016-07-01 08:22:01 -070092 PACK(Snorm4x8);
93 PACK(Unorm4x8);
94 PACK(Snorm2x16);
95 PACK(Unorm2x16);
96 PACK(Half2x16);
97 PACK(Double2x32);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040098 fIntrinsicMap[String("length")] = ALL_GLSL(Length);
99 fIntrinsicMap[String("distance")] = ALL_GLSL(Distance);
100 fIntrinsicMap[String("cross")] = ALL_GLSL(Cross);
101 fIntrinsicMap[String("normalize")] = ALL_GLSL(Normalize);
John Stiles0d19fb42020-12-10 17:04:37 -0500102 fIntrinsicMap[String("faceforward")] = ALL_GLSL(FaceForward);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400103 fIntrinsicMap[String("reflect")] = ALL_GLSL(Reflect);
104 fIntrinsicMap[String("refract")] = ALL_GLSL(Refract);
John Stilese7dc7cb2020-12-22 15:37:14 -0500105 fIntrinsicMap[String("bitCount")] = ALL_SPIRV(BitCount);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400106 fIntrinsicMap[String("findLSB")] = ALL_GLSL(FindILsb);
107 fIntrinsicMap[String("findMSB")] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
108 fIntrinsicMap[String("dFdx")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400109 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700110 fIntrinsicMap[String("dFdy")] = SPECIAL(DFdy);
Chris Dalton09212192018-11-13 15:07:24 -0500111 fIntrinsicMap[String("fwidth")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFwidth,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400112 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400113 fIntrinsicMap[String("makeSampler2D")] = SPECIAL(SampledImage);
114
Ethan Nicholas13863662019-07-29 13:05:15 -0400115 fIntrinsicMap[String("sample")] = SPECIAL(Texture);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400116 fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
Greg Daniel64773e62016-11-22 09:44:03 -0500117
John Stilescc9ff002020-12-09 18:39:41 -0500118 fIntrinsicMap[String("floatBitsToInt")] = ALL_SPIRV(Bitcast);
119 fIntrinsicMap[String("floatBitsToUint")] = ALL_SPIRV(Bitcast);
120 fIntrinsicMap[String("intBitsToFloat")] = ALL_SPIRV(Bitcast);
121 fIntrinsicMap[String("uintBitsToFloat")] = ALL_SPIRV(Bitcast);
122
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400123 fIntrinsicMap[String("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400124 SpvOpUndef, SpvOpUndef, SpvOpAny);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400125 fIntrinsicMap[String("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400126 SpvOpUndef, SpvOpUndef, SpvOpAll);
Brian Osman540c13a2020-11-24 16:55:34 -0500127 fIntrinsicMap[String("not")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
128 SpvOpUndef, SpvOpUndef,
129 SpvOpLogicalNot);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400130 fIntrinsicMap[String("equal")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400131 SpvOpFOrdEqual, SpvOpIEqual,
132 SpvOpIEqual, SpvOpLogicalEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400133 fIntrinsicMap[String("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400134 SpvOpFOrdNotEqual, SpvOpINotEqual,
135 SpvOpINotEqual,
136 SpvOpLogicalNotEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400137 fIntrinsicMap[String("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500138 SpvOpFOrdLessThan, SpvOpSLessThan,
139 SpvOpULessThan, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400140 fIntrinsicMap[String("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500141 SpvOpFOrdLessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400142 SpvOpSLessThanEqual,
143 SpvOpULessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400144 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400145 fIntrinsicMap[String("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500146 SpvOpFOrdGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400147 SpvOpSGreaterThan,
148 SpvOpUGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400149 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400150 fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500151 SpvOpFOrdGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400152 SpvOpSGreaterThanEqual,
153 SpvOpUGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400154 SpvOpUndef);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400155 fIntrinsicMap[String("EmitVertex")] = ALL_SPIRV(EmitVertex);
156 fIntrinsicMap[String("EndPrimitive")] = ALL_SPIRV(EndPrimitive);
ethannicholasb3058bd2016-07-01 08:22:01 -0700157// interpolateAt* not yet supported...
158}
159
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400160void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700161 out.write((const char*) &word, sizeof(word));
ethannicholasb3058bd2016-07-01 08:22:01 -0700162}
163
ethannicholasd598f792016-07-25 10:08:54 -0700164static bool is_float(const Context& context, const Type& type) {
Ethan Nicholas0df21132018-07-10 09:37:51 -0400165 if (type.columns() > 1) {
ethannicholasd598f792016-07-25 10:08:54 -0700166 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700167 }
John Stiles123501f2020-12-09 10:08:13 -0500168 return type.isFloat();
ethannicholasb3058bd2016-07-01 08:22:01 -0700169}
170
ethannicholasd598f792016-07-25 10:08:54 -0700171static bool is_signed(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500172 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700173 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700174 }
John Stiles123501f2020-12-09 10:08:13 -0500175 return type.isSigned();
ethannicholasb3058bd2016-07-01 08:22:01 -0700176}
177
ethannicholasd598f792016-07-25 10:08:54 -0700178static bool is_unsigned(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500179 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700180 return is_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700181 }
John Stiles123501f2020-12-09 10:08:13 -0500182 return type.isUnsigned();
ethannicholasb3058bd2016-07-01 08:22:01 -0700183}
184
ethannicholasd598f792016-07-25 10:08:54 -0700185static bool is_bool(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500186 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700187 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700188 }
John Stiles123501f2020-12-09 10:08:13 -0500189 return type.isBoolean();
ethannicholasb3058bd2016-07-01 08:22:01 -0700190}
191
ethannicholasd598f792016-07-25 10:08:54 -0700192static bool is_out(const Variable& var) {
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400193 return (var.modifiers().fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700194}
195
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400196void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400197 SkASSERT(opCode != SpvOpLoad || &out != &fConstantBuffer);
198 SkASSERT(opCode != SpvOpUndef);
ethannicholasb3058bd2016-07-01 08:22:01 -0700199 switch (opCode) {
200 case SpvOpReturn: // fall through
201 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700202 case SpvOpKill: // fall through
Ethan Nicholas7fb39362020-12-16 15:25:19 -0500203 case SpvOpSwitch: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700204 case SpvOpBranch: // fall through
205 case SpvOpBranchConditional:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400206 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700207 fCurrentBlock = 0;
208 break;
209 case SpvOpConstant: // fall through
210 case SpvOpConstantTrue: // fall through
211 case SpvOpConstantFalse: // fall through
212 case SpvOpConstantComposite: // fall through
213 case SpvOpTypeVoid: // fall through
214 case SpvOpTypeInt: // fall through
215 case SpvOpTypeFloat: // fall through
216 case SpvOpTypeBool: // fall through
217 case SpvOpTypeVector: // fall through
218 case SpvOpTypeMatrix: // fall through
219 case SpvOpTypeArray: // fall through
220 case SpvOpTypePointer: // fall through
221 case SpvOpTypeFunction: // fall through
222 case SpvOpTypeRuntimeArray: // fall through
223 case SpvOpTypeStruct: // fall through
224 case SpvOpTypeImage: // fall through
225 case SpvOpTypeSampledImage: // fall through
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400226 case SpvOpTypeSampler: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700227 case SpvOpVariable: // fall through
228 case SpvOpFunction: // fall through
229 case SpvOpFunctionParameter: // fall through
230 case SpvOpFunctionEnd: // fall through
231 case SpvOpExecutionMode: // fall through
232 case SpvOpMemoryModel: // fall through
233 case SpvOpCapability: // fall through
234 case SpvOpExtInstImport: // fall through
235 case SpvOpEntryPoint: // fall through
236 case SpvOpSource: // fall through
237 case SpvOpSourceExtension: // fall through
238 case SpvOpName: // fall through
239 case SpvOpMemberName: // fall through
240 case SpvOpDecorate: // fall through
241 case SpvOpMemberDecorate:
242 break;
243 default:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400244 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700245 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700246 this->writeWord((length << 16) | opCode, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700247}
248
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400249void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
Ethan Nicholas7fb39362020-12-16 15:25:19 -0500250 SkASSERT(!fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700251 fCurrentBlock = label;
252 this->writeInstruction(SpvOpLabel, label, out);
253}
254
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400255void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700256 this->writeOpCode(opCode, 1, out);
257}
258
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400259void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700260 this->writeOpCode(opCode, 2, out);
261 this->writeWord(word1, out);
262}
263
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700264void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputStream& out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400265 out.write(string, length);
ethannicholasb3058bd2016-07-01 08:22:01 -0700266 switch (length % 4) {
267 case 1:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500268 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400269 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700270 case 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500271 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400272 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700273 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500274 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700275 break;
276 default:
277 this->writeWord(0, out);
278 }
279}
280
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700281void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out) {
282 this->writeOpCode(opCode, 1 + (string.fLength + 4) / 4, out);
283 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700284}
285
286
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700287void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400288 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700289 this->writeOpCode(opCode, 2 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700290 this->writeWord(word1, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700291 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700292}
293
Greg Daniel64773e62016-11-22 09:44:03 -0500294void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700295 StringFragment string, OutputStream& out) {
296 this->writeOpCode(opCode, 3 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700297 this->writeWord(word1, out);
298 this->writeWord(word2, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700299 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700300}
301
Greg Daniel64773e62016-11-22 09:44:03 -0500302void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400303 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700304 this->writeOpCode(opCode, 3, out);
305 this->writeWord(word1, out);
306 this->writeWord(word2, out);
307}
308
Greg Daniel64773e62016-11-22 09:44:03 -0500309void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400310 int32_t word3, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700311 this->writeOpCode(opCode, 4, out);
312 this->writeWord(word1, out);
313 this->writeWord(word2, out);
314 this->writeWord(word3, out);
315}
316
Greg Daniel64773e62016-11-22 09:44:03 -0500317void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400318 int32_t word3, int32_t word4, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700319 this->writeOpCode(opCode, 5, out);
320 this->writeWord(word1, out);
321 this->writeWord(word2, out);
322 this->writeWord(word3, out);
323 this->writeWord(word4, out);
324}
325
Greg Daniel64773e62016-11-22 09:44:03 -0500326void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
327 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400328 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700329 this->writeOpCode(opCode, 6, out);
330 this->writeWord(word1, out);
331 this->writeWord(word2, out);
332 this->writeWord(word3, out);
333 this->writeWord(word4, out);
334 this->writeWord(word5, out);
335}
336
Greg Daniel64773e62016-11-22 09:44:03 -0500337void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700338 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400339 int32_t word6, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700340 this->writeOpCode(opCode, 7, out);
341 this->writeWord(word1, out);
342 this->writeWord(word2, out);
343 this->writeWord(word3, out);
344 this->writeWord(word4, out);
345 this->writeWord(word5, out);
346 this->writeWord(word6, out);
347}
348
Greg Daniel64773e62016-11-22 09:44:03 -0500349void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700350 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400351 int32_t word6, int32_t word7, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700352 this->writeOpCode(opCode, 8, out);
353 this->writeWord(word1, out);
354 this->writeWord(word2, out);
355 this->writeWord(word3, out);
356 this->writeWord(word4, out);
357 this->writeWord(word5, out);
358 this->writeWord(word6, out);
359 this->writeWord(word7, out);
360}
361
Greg Daniel64773e62016-11-22 09:44:03 -0500362void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700363 int32_t word3, int32_t word4, int32_t word5,
364 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400365 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700366 this->writeOpCode(opCode, 9, out);
367 this->writeWord(word1, out);
368 this->writeWord(word2, out);
369 this->writeWord(word3, out);
370 this->writeWord(word4, out);
371 this->writeWord(word5, out);
372 this->writeWord(word6, out);
373 this->writeWord(word7, out);
374 this->writeWord(word8, out);
375}
376
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400377void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700378 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
379 if (fCapabilities & bit) {
380 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
381 }
382 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400383 if (fProgram.fKind == Program::kGeometry_Kind) {
384 this->writeInstruction(SpvOpCapability, SpvCapabilityGeometry, out);
385 }
Ethan Nicholas81d15112018-07-13 12:48:50 -0400386 else {
387 this->writeInstruction(SpvOpCapability, SpvCapabilityShader, out);
388 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700389}
390
391SpvId SPIRVCodeGenerator::nextId() {
392 return fIdCount++;
393}
394
Ethan Nicholas19671772016-11-28 16:30:17 -0500395void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
396 SpvId resultId) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400397 this->writeInstruction(SpvOpName, resultId, String(type.name()).c_str(), fNameBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700398 // go ahead and write all of the field types, so we don't inadvertently write them while we're
399 // in the middle of writing the struct instruction
400 std::vector<SpvId> types;
401 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500402 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700403 }
404 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
405 this->writeWord(resultId, fConstantBuffer);
406 for (SpvId id : types) {
407 this->writeWord(id, fConstantBuffer);
408 }
409 size_t offset = 0;
410 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400411 const Type::Field& field = type.fields()[i];
John Stiles21f5f452020-11-30 09:57:59 -0500412 if (!MemoryLayout::LayoutIsSupported(*field.fType)) {
John Stiles0023c0c2020-11-16 13:32:18 -0500413 fErrors.error(type.fOffset, "type '" + field.fType->name() + "' is not permitted here");
414 return;
415 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400416 size_t size = memoryLayout.size(*field.fType);
417 size_t alignment = memoryLayout.alignment(*field.fType);
418 const Layout& fieldLayout = field.fModifiers.fLayout;
Ethan Nicholas19671772016-11-28 16:30:17 -0500419 if (fieldLayout.fOffset >= 0) {
Greg Danieldbd44c72017-01-24 15:12:12 -0500420 if (fieldLayout.fOffset < (int) offset) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700421 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400422 "offset of field '" + field.fName + "' must be at "
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500423 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -0500424 }
425 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700426 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400427 "offset of field '" + field.fName + "' must be a multiple"
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500428 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -0500429 }
430 offset = fieldLayout.fOffset;
431 } else {
432 size_t mod = offset % alignment;
433 if (mod) {
434 offset += alignment - mod;
435 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700436 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400437 this->writeInstruction(SpvOpMemberName, resultId, i, field.fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500438 this->writeLayout(fieldLayout, resultId, i);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400439 if (field.fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -0500440 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700441 (SpvId) offset, fDecorationBuffer);
442 }
John Stiles9aeed132020-11-24 17:36:06 -0500443 if (field.fType->isMatrix()) {
Greg Daniel64773e62016-11-22 09:44:03 -0500444 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -0700445 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500446 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400447 (SpvId) memoryLayout.stride(*field.fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800448 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700449 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400450 if (!field.fType->highPrecision()) {
451 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i,
452 SpvDecorationRelaxedPrecision, fDecorationBuffer);
453 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700454 offset += size;
John Stilesc0c51062020-12-03 17:16:29 -0500455 if ((field.fType->isArray() || field.fType->isStruct()) && offset % alignment != 0) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700456 offset += alignment - offset % alignment;
457 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700458 }
459}
460
Ethan Nicholase2c49992020-10-05 11:49:11 -0400461const Type& SPIRVCodeGenerator::getActualType(const Type& type) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500462 if (type.isFloat()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400463 return *fContext.fFloat_Type;
464 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500465 if (type.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400466 return *fContext.fInt_Type;
467 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500468 if (type.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400469 return *fContext.fUInt_Type;
470 }
John Stiles9aeed132020-11-24 17:36:06 -0500471 if (type.isMatrix() || type.isVector()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400472 if (type.componentType() == *fContext.fHalf_Type) {
473 return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
474 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400475 if (type.componentType() == *fContext.fShort_Type ||
476 type.componentType() == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400477 return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
478 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400479 if (type.componentType() == *fContext.fUShort_Type ||
480 type.componentType() == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400481 return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
482 }
483 }
484 return type;
485}
486
ethannicholasb3058bd2016-07-01 08:22:01 -0700487SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800488 return this->getType(type, fDefaultLayout);
489}
490
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400491SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400492 const Type& type = this->getActualType(rawType);
Jim Van Verthf3ec9832020-10-21 16:09:57 -0400493 String key = type.name();
John Stilesc0c51062020-12-03 17:16:29 -0500494 if (type.isStruct() || type.isArray()) {
Jim Van Verthf3ec9832020-10-21 16:09:57 -0400495 key += to_string((int)layout.fStd);
496 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800497 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700498 if (entry == fTypeMap.end()) {
499 SpvId result = this->nextId();
Ethan Nicholase6592142020-09-08 10:22:09 -0400500 switch (type.typeKind()) {
501 case Type::TypeKind::kScalar:
John Stiles4a7dc462020-11-25 11:08:08 -0500502 if (type.isBoolean()) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700503 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500504 } else if (type == *fContext.fInt_Type || type == *fContext.fShort_Type ||
505 type == *fContext.fIntLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700506 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500507 } else if (type == *fContext.fUInt_Type || type == *fContext.fUShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700508 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500509 } else if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type ||
510 type == *fContext.fFloatLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700511 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700512 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400513 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700514 }
515 break;
John Stilesfd41d872020-11-25 22:39:45 -0500516 case Type::TypeKind::kEnum:
517 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
518 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400519 case Type::TypeKind::kVector:
Greg Daniel64773e62016-11-22 09:44:03 -0500520 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800521 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700522 type.columns(), fConstantBuffer);
523 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400524 case Type::TypeKind::kMatrix:
Greg Daniel64773e62016-11-22 09:44:03 -0500525 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800526 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700527 type.columns(), fConstantBuffer);
528 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400529 case Type::TypeKind::kStruct:
ethannicholas8ac838d2016-11-22 08:39:36 -0800530 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700531 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400532 case Type::TypeKind::kArray: {
John Stiles21f5f452020-11-30 09:57:59 -0500533 if (!MemoryLayout::LayoutIsSupported(type)) {
534 fErrors.error(type.fOffset, "type '" + type.name() + "' is not permitted here");
535 return this->nextId();
536 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700537 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700538 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500539 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800540 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700541 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500542 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400543 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800544 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700545 } else {
John Stiles5570c512020-11-19 17:58:07 -0500546 // We shouldn't have any runtime-sized arrays right now
547 fErrors.error(type.fOffset, "runtime-sized arrays are not supported in SPIR-V");
Greg Daniel64773e62016-11-22 09:44:03 -0500548 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800549 this->getType(type.componentType(), layout),
550 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400551 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
552 (int32_t) layout.stride(type),
553 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700554 }
555 break;
556 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400557 case Type::TypeKind::kSampler: {
Greg Daniel64773e62016-11-22 09:44:03 -0500558 SpvId image = result;
559 if (SpvDimSubpassData != type.dimensions()) {
Stephen White792e2302019-08-09 13:33:51 -0400560 image = this->getType(type.textureType(), layout);
Greg Daniel64773e62016-11-22 09:44:03 -0500561 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400562 if (SpvDimBuffer == type.dimensions()) {
563 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
564 }
Greg Daniel64773e62016-11-22 09:44:03 -0500565 if (SpvDimSubpassData != type.dimensions()) {
566 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
567 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700568 break;
569 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400570 case Type::TypeKind::kSeparateSampler: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400571 this->writeInstruction(SpvOpTypeSampler, result, fConstantBuffer);
572 break;
573 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400574 case Type::TypeKind::kTexture: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400575 this->writeInstruction(SpvOpTypeImage, result,
576 this->getType(*fContext.fFloat_Type, layout),
John Stilesc0c51062020-12-03 17:16:29 -0500577 type.dimensions(), type.isDepth(), type.isArrayedTexture(),
Stephen White792e2302019-08-09 13:33:51 -0400578 type.isMultisampled(), type.isSampled() ? 1 : 2,
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400579 SpvImageFormatUnknown, fConstantBuffer);
580 fImageTypeMap[key] = result;
581 break;
582 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700583 default:
ethannicholasd598f792016-07-25 10:08:54 -0700584 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700585 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
586 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500587#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700588 ABORT("invalid type: %s", type.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500589#endif
ethannicholasb3058bd2016-07-01 08:22:01 -0700590 }
591 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800592 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700593 return result;
594 }
595 return entry->second;
596}
597
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400598SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400599 SkASSERT(type.typeKind() == Type::TypeKind::kSampler);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400600 this->getType(type);
601 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400602 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400603 return fImageTypeMap[key];
604}
605
ethannicholasd598f792016-07-25 10:08:54 -0700606SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400607 String key = to_string(this->getType(function.returnType())) + "(";
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400608 String separator;
Brian Osman5bf3e202020-10-13 10:34:18 -0400609 const std::vector<const Variable*>& parameters = function.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400610 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700611 key += separator;
612 separator = ", ";
Ethan Nicholased84b732020-10-08 11:45:44 -0400613 key += to_string(this->getType(parameters[i]->type()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700614 }
615 key += ")";
616 auto entry = fTypeMap.find(key);
617 if (entry == fTypeMap.end()) {
618 SpvId result = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -0400619 int32_t length = 3 + (int32_t) parameters.size();
620 SpvId returnType = this->getType(function.returnType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700621 std::vector<SpvId> parameterTypes;
Ethan Nicholased84b732020-10-08 11:45:44 -0400622 for (size_t i = 0; i < parameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500623 // glslang seems to treat all function arguments as pointers whether they need to be or
624 // not. I was initially puzzled by this until I ran bizarre failures with certain
625 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700626 // failure case:
627 //
628 // void sphere(float x) {
629 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500630 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700631 // void map() {
632 // sphere(1.0);
633 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500634 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700635 // void main() {
636 // for (int i = 0; i < 1; i++) {
637 // map();
638 // }
639 // }
640 //
Greg Daniel64773e62016-11-22 09:44:03 -0500641 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
642 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700643 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
644 // the spec makes this make sense.
645// if (is_out(function->fParameters[i])) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400646 parameterTypes.push_back(this->getPointerType(parameters[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -0700647 SpvStorageClassFunction));
648// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700649// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700650// }
651 }
652 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
653 this->writeWord(result, fConstantBuffer);
654 this->writeWord(returnType, fConstantBuffer);
655 for (SpvId id : parameterTypes) {
656 this->writeWord(id, fConstantBuffer);
657 }
658 fTypeMap[key] = result;
659 return result;
660 }
661 return entry->second;
662}
663
ethannicholas8ac838d2016-11-22 08:39:36 -0800664SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
665 return this->getPointerType(type, fDefaultLayout, storageClass);
666}
667
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400668SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700669 SpvStorageClass_ storageClass) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400670 const Type& type = this->getActualType(rawType);
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500671 String key = type.displayName() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700672 auto entry = fTypeMap.find(key);
673 if (entry == fTypeMap.end()) {
674 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500675 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700676 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700677 fTypeMap[key] = result;
678 return result;
679 }
680 return entry->second;
681}
682
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400683SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400684 switch (expr.kind()) {
685 case Expression::Kind::kBinary:
John Stiles81365af2020-08-18 09:24:00 -0400686 return this->writeBinaryExpression(expr.as<BinaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400687 case Expression::Kind::kBoolLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400688 return this->writeBoolLiteral(expr.as<BoolLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400689 case Expression::Kind::kConstructor:
John Stiles81365af2020-08-18 09:24:00 -0400690 return this->writeConstructor(expr.as<Constructor>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400691 case Expression::Kind::kIntLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400692 return this->writeIntLiteral(expr.as<IntLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400693 case Expression::Kind::kFieldAccess:
John Stiles81365af2020-08-18 09:24:00 -0400694 return this->writeFieldAccess(expr.as<FieldAccess>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400695 case Expression::Kind::kFloatLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400696 return this->writeFloatLiteral(expr.as<FloatLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400697 case Expression::Kind::kFunctionCall:
John Stiles81365af2020-08-18 09:24:00 -0400698 return this->writeFunctionCall(expr.as<FunctionCall>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400699 case Expression::Kind::kPrefix:
John Stiles81365af2020-08-18 09:24:00 -0400700 return this->writePrefixExpression(expr.as<PrefixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400701 case Expression::Kind::kPostfix:
John Stiles81365af2020-08-18 09:24:00 -0400702 return this->writePostfixExpression(expr.as<PostfixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400703 case Expression::Kind::kSwizzle:
John Stiles81365af2020-08-18 09:24:00 -0400704 return this->writeSwizzle(expr.as<Swizzle>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400705 case Expression::Kind::kVariableReference:
John Stiles81365af2020-08-18 09:24:00 -0400706 return this->writeVariableReference(expr.as<VariableReference>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400707 case Expression::Kind::kTernary:
John Stiles81365af2020-08-18 09:24:00 -0400708 return this->writeTernaryExpression(expr.as<TernaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400709 case Expression::Kind::kIndex:
John Stiles81365af2020-08-18 09:24:00 -0400710 return this->writeIndexExpression(expr.as<IndexExpression>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700711 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500712#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700713 ABORT("unsupported expression: %s", expr.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500714#endif
715 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700716 }
717 return -1;
718}
719
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400720SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400721 const FunctionDeclaration& function = c.function();
John Stiles8e3b6be2020-10-13 11:14:08 -0400722 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400723 auto intrinsic = fIntrinsicMap.find(function.name());
John Stiles93e661a2020-12-08 16:17:00 -0500724 if (intrinsic == fIntrinsicMap.end()) {
725 fErrors.error(c.fOffset, "unsupported intrinsic '" + function.description() + "'");
726 return -1;
727 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700728 int32_t intrinsicId;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400729 if (arguments.size() > 0) {
730 const Type& type = arguments[0]->type();
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400731 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
732 intrinsicId = std::get<1>(intrinsic->second);
733 } else if (is_signed(fContext, type)) {
734 intrinsicId = std::get<2>(intrinsic->second);
735 } else if (is_unsigned(fContext, type)) {
736 intrinsicId = std::get<3>(intrinsic->second);
737 } else if (is_bool(fContext, type)) {
738 intrinsicId = std::get<4>(intrinsic->second);
739 } else {
740 intrinsicId = std::get<1>(intrinsic->second);
741 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700742 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400743 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700744 }
745 switch (std::get<0>(intrinsic->second)) {
746 case kGLSL_STD_450_IntrinsicKind: {
747 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400748 std::vector<SpvId> argumentIds;
749 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400750 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400751 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400752 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400753 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400754 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700755 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400756 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400757 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700758 this->writeWord(result, out);
759 this->writeWord(fGLSLExtendedInstructions, out);
760 this->writeWord(intrinsicId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400761 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700762 this->writeWord(id, out);
763 }
764 return result;
765 }
766 case kSPIRV_IntrinsicKind: {
Brian Osman46787d52020-11-24 14:18:23 -0500767 // GLSL supports dot(float, float), but SPIR-V does not. Convert it to FMul
John Stiles9aeed132020-11-24 17:36:06 -0500768 if (intrinsicId == SpvOpDot && arguments[0]->type().isScalar()) {
Brian Osman46787d52020-11-24 14:18:23 -0500769 intrinsicId = SpvOpFMul;
770 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700771 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400772 std::vector<SpvId> argumentIds;
773 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400774 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400775 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400776 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400777 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400778 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700779 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400780 if (c.type() != *fContext.fVoid_Type) {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400781 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400782 this->writeWord(this->getType(c.type()), out);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400783 this->writeWord(result, out);
784 } else {
785 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
786 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400787 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700788 this->writeWord(id, out);
789 }
790 return result;
791 }
792 case kSpecial_IntrinsicKind:
793 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
794 default:
John Stiles93e661a2020-12-08 16:17:00 -0500795 fErrors.error(c.fOffset, "unsupported intrinsic '" + function.description() + "'");
796 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700797 }
798}
799
John Stiles8e3b6be2020-10-13 11:14:08 -0400800std::vector<SpvId> SPIRVCodeGenerator::vectorize(const ExpressionArray& args, OutputStream& out) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500801 int vectorSize = 0;
802 for (const auto& a : args) {
John Stiles9aeed132020-11-24 17:36:06 -0500803 if (a->type().isVector()) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500804 if (vectorSize) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400805 SkASSERT(a->type().columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500806 }
807 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400808 vectorSize = a->type().columns();
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500809 }
810 }
811 }
812 std::vector<SpvId> result;
John Stiles8e3b6be2020-10-13 11:14:08 -0400813 result.reserve(args.size());
Ethan Nicholas30d30222020-09-11 12:27:26 -0400814 for (const auto& arg : args) {
815 const Type& argType = arg->type();
816 SpvId raw = this->writeExpression(*arg, out);
John Stiles9aeed132020-11-24 17:36:06 -0500817 if (vectorSize && argType.isScalar()) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500818 SpvId vector = this->nextId();
819 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400820 this->writeWord(this->getType(argType.toCompound(fContext, vectorSize, 1)), out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500821 this->writeWord(vector, out);
822 for (int i = 0; i < vectorSize; i++) {
823 this->writeWord(raw, out);
824 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400825 this->writePrecisionModifier(argType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500826 result.push_back(vector);
827 } else {
828 result.push_back(raw);
829 }
830 }
831 return result;
832}
833
834void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
835 SpvId signedInst, SpvId unsignedInst,
836 const std::vector<SpvId>& args,
837 OutputStream& out) {
838 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
839 this->writeWord(this->getType(type), out);
840 this->writeWord(id, out);
841 this->writeWord(fGLSLExtendedInstructions, out);
842
843 if (is_float(fContext, type)) {
844 this->writeWord(floatInst, out);
845 } else if (is_signed(fContext, type)) {
846 this->writeWord(signedInst, out);
847 } else if (is_unsigned(fContext, type)) {
848 this->writeWord(unsignedInst, out);
849 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400850 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500851 }
852 for (SpvId a : args) {
853 this->writeWord(a, out);
854 }
855}
856
Greg Daniel64773e62016-11-22 09:44:03 -0500857SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400858 OutputStream& out) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400859 const ExpressionArray& arguments = c.arguments();
ethannicholasb3058bd2016-07-01 08:22:01 -0700860 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400861 const Type& callType = c.type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700862 switch (kind) {
863 case kAtan_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400864 std::vector<SpvId> argumentIds;
865 for (const std::unique_ptr<Expression>& arg : arguments) {
866 argumentIds.push_back(this->writeExpression(*arg, out));
ethannicholasb3058bd2016-07-01 08:22:01 -0700867 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400868 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400869 this->writeWord(this->getType(callType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700870 this->writeWord(result, out);
871 this->writeWord(fGLSLExtendedInstructions, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400872 this->writeWord(argumentIds.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
873 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700874 this->writeWord(id, out);
875 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400876 break;
877 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400878 case kSampledImage_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400879 SkASSERT(arguments.size() == 2);
880 SpvId img = this->writeExpression(*arguments[0], out);
881 SpvId sampler = this->writeExpression(*arguments[1], out);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400882 this->writeInstruction(SpvOpSampledImage,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400883 this->getType(callType),
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400884 result,
885 img,
886 sampler,
887 out);
888 break;
889 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400890 case kSubpassLoad_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400891 SpvId img = this->writeExpression(*arguments[0], out);
John Stiles8e3b6be2020-10-13 11:14:08 -0400892 ExpressionArray args;
John Stilesf4bda742020-10-14 16:57:41 -0400893 args.reserve_back(2);
John Stiles8e3b6be2020-10-13 11:14:08 -0400894 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
895 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
Ethan Nicholas30d30222020-09-11 12:27:26 -0400896 Constructor ctor(-1, fContext.fInt2_Type.get(), std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400897 SpvId coords = this->writeConstantVector(ctor);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400898 if (arguments.size() == 1) {
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400899 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400900 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400901 result,
902 img,
903 coords,
904 out);
905 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400906 SkASSERT(arguments.size() == 2);
907 SpvId sample = this->writeExpression(*arguments[1], out);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400908 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400909 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400910 result,
911 img,
912 coords,
913 SpvImageOperandsSampleMask,
914 sample,
915 out);
916 }
917 break;
918 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700919 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500920 SpvOp_ op = SpvOpImageSampleImplicitLod;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400921 const Type& arg1Type = arguments[1]->type();
922 switch (arguments[0]->type().dimensions()) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500923 case SpvDim1D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400924 if (arg1Type == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500925 op = SpvOpImageSampleProjImplicitLod;
926 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400927 SkASSERT(arg1Type == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500928 }
929 break;
930 case SpvDim2D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400931 if (arg1Type == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500932 op = SpvOpImageSampleProjImplicitLod;
933 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400934 SkASSERT(arg1Type == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500935 }
936 break;
937 case SpvDim3D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400938 if (arg1Type == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500939 op = SpvOpImageSampleProjImplicitLod;
940 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400941 SkASSERT(arg1Type == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500942 }
943 break;
944 case SpvDimCube: // fall through
945 case SpvDimRect: // fall through
946 case SpvDimBuffer: // fall through
947 case SpvDimSubpassData:
948 break;
949 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400950 SpvId type = this->getType(callType);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400951 SpvId sampler = this->writeExpression(*arguments[0], out);
952 SpvId uv = this->writeExpression(*arguments[1], out);
953 if (arguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500954 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700955 SpvImageOperandsBiasMask,
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400956 this->writeExpression(*arguments[2], out),
ethannicholasb3058bd2016-07-01 08:22:01 -0700957 out);
958 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400959 SkASSERT(arguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500960 if (fProgram.fSettings.fSharpenTextures) {
961 FloatLiteral lodBias(fContext, -1, -0.5);
962 this->writeInstruction(op, type, result, sampler, uv,
963 SpvImageOperandsBiasMask,
964 this->writeFloatLiteral(lodBias),
965 out);
966 } else {
967 this->writeInstruction(op, type, result, sampler, uv,
968 out);
969 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700970 }
971 break;
972 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500973 case kMod_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400974 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400975 SkASSERT(args.size() == 2);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400976 const Type& operandType = arguments[0]->type();
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500977 SpvOp_ op;
978 if (is_float(fContext, operandType)) {
979 op = SpvOpFMod;
980 } else if (is_signed(fContext, operandType)) {
981 op = SpvOpSMod;
982 } else if (is_unsigned(fContext, operandType)) {
983 op = SpvOpUMod;
984 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400985 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500986 return 0;
987 }
988 this->writeOpCode(op, 5, out);
989 this->writeWord(this->getType(operandType), out);
990 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500991 this->writeWord(args[0], out);
992 this->writeWord(args[1], out);
993 break;
994 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700995 case kDFdy_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400996 SpvId fn = this->writeExpression(*arguments[0], out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700997 this->writeOpCode(SpvOpDPdy, 4, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400998 this->writeWord(this->getType(callType), out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700999 this->writeWord(result, out);
1000 this->writeWord(fn, out);
1001 if (fProgram.fSettings.fFlipY) {
1002 // Flipping Y also negates the Y derivatives.
1003 SpvId flipped = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001004 this->writeInstruction(SpvOpFNegate, this->getType(callType), flipped, result,
1005 out);
1006 this->writePrecisionModifier(callType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -07001007 return flipped;
1008 }
1009 break;
1010 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001011 case kClamp_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001012 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001013 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001014 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001015 GLSLstd450UClamp, args, out);
1016 break;
1017 }
1018 case kMax_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001019 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001020 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001021 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMax, GLSLstd450SMax,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001022 GLSLstd450UMax, args, out);
1023 break;
1024 }
1025 case kMin_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001026 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001027 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001028 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMin, GLSLstd450SMin,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001029 GLSLstd450UMin, args, out);
1030 break;
1031 }
1032 case kMix_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001033 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001034 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001035 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMix, SpvOpUndef,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001036 SpvOpUndef, args, out);
1037 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -05001038 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001039 case kSaturate_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001040 SkASSERT(arguments.size() == 1);
John Stiles8e3b6be2020-10-13 11:14:08 -04001041 ExpressionArray finalArgs;
John Stilesf4bda742020-10-14 16:57:41 -04001042 finalArgs.reserve_back(3);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001043 finalArgs.push_back(arguments[0]->clone());
John Stiles8e3b6be2020-10-13 11:14:08 -04001044 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1045 /*value=*/0));
1046 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1047 /*value=*/1));
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001048 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001049 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001050 GLSLstd450UClamp, spvArgs, out);
1051 break;
1052 }
Brian Osman6ba3be12020-11-13 16:32:52 -05001053 case kSmoothStep_SpecialIntrinsic: {
1054 std::vector<SpvId> args = this->vectorize(arguments, out);
1055 SkASSERT(args.size() == 3);
1056 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450SmoothStep, SpvOpUndef,
1057 SpvOpUndef, args, out);
1058 break;
1059 }
1060 case kStep_SpecialIntrinsic: {
1061 std::vector<SpvId> args = this->vectorize(arguments, out);
1062 SkASSERT(args.size() == 2);
1063 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450Step, SpvOpUndef,
1064 SpvOpUndef, args, out);
1065 break;
1066 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001067 }
1068 return result;
1069}
1070
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001071SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001072 const FunctionDeclaration& function = c.function();
John Stiles8e3b6be2020-10-13 11:14:08 -04001073 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001074 const auto& entry = fFunctionMap.find(&function);
ethannicholasb3058bd2016-07-01 08:22:01 -07001075 if (entry == fFunctionMap.end()) {
1076 return this->writeIntrinsicCall(c, out);
1077 }
1078 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001079 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001080 std::vector<SpvId> argumentIds;
1081 for (size_t i = 0; i < arguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001082 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001083 // passed directly
1084 SpvId tmpVar;
1085 // if we need a temporary var to store this argument, this is the value to store in the var
1086 SpvId tmpValueId;
Ethan Nicholased84b732020-10-08 11:45:44 -04001087 if (is_out(*function.parameters()[i])) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001088 std::unique_ptr<LValue> lv = this->getLValue(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001089 SpvId ptr = lv->getPointer();
1090 if (ptr) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001091 argumentIds.push_back(ptr);
ethannicholasb3058bd2016-07-01 08:22:01 -07001092 continue;
1093 } else {
1094 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1095 // copy it into a temp, call the function, read the value out of the temp, and then
1096 // update the lvalue.
1097 tmpValueId = lv->load(out);
1098 tmpVar = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001099 lvalues.push_back(std::make_tuple(tmpVar, &arguments[i]->type(), std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001100 }
1101 } else {
1102 // see getFunctionType for an explanation of why we're always using pointer parameters
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001103 tmpValueId = this->writeExpression(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001104 tmpVar = this->nextId();
1105 }
Greg Daniel64773e62016-11-22 09:44:03 -05001106 this->writeInstruction(SpvOpVariable,
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001107 this->getPointerType(arguments[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001108 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001109 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001110 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001111 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001112 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001113 argumentIds.push_back(tmpVar);
ethannicholasb3058bd2016-07-01 08:22:01 -07001114 }
1115 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001116 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001117 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001118 this->writeWord(result, out);
1119 this->writeWord(entry->second, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001120 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001121 this->writeWord(id, out);
1122 }
1123 // now that the call is complete, we may need to update some lvalues with the new values of out
1124 // arguments
1125 for (const auto& tuple : lvalues) {
1126 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001127 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1128 out);
1129 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001130 std::get<2>(tuple)->store(load, out);
1131 }
1132 return result;
1133}
1134
ethannicholasf789b382016-08-03 12:43:36 -07001135SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001136 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001137 SkASSERT(type.isVector() && c.isCompileTimeConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001138 SpvId result = this->nextId();
1139 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001140 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1141 arguments.push_back(this->writeExpression(*arg, fConstantBuffer));
ethannicholasb3058bd2016-07-01 08:22:01 -07001142 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001143 SpvId typeId = this->getType(type);
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001144 if (c.arguments().size() == 1) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001145 // with a single argument, a vector will have all of its entries equal to the argument
Ethan Nicholas30d30222020-09-11 12:27:26 -04001146 this->writeOpCode(SpvOpConstantComposite, 3 + type.columns(), fConstantBuffer);
1147 this->writeWord(typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001148 this->writeWord(result, fConstantBuffer);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001149 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001150 this->writeWord(arguments[0], fConstantBuffer);
1151 }
1152 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001153 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.arguments().size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001154 fConstantBuffer);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001155 this->writeWord(typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001156 this->writeWord(result, fConstantBuffer);
1157 for (SpvId id : arguments) {
1158 this->writeWord(id, fConstantBuffer);
1159 }
1160 }
1161 return result;
1162}
1163
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001164SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001165 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001166 SkASSERT(c.arguments().size() == 1);
1167 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001168 SkASSERT(constructorType.isFloat());
1169 SkASSERT(argType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001170 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001171 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001172 if (argType.isSigned()) {
1173 this->writeInstruction(SpvOpConvertSToF, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001174 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001175 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001176 SkASSERT(argType.isUnsigned());
1177 this->writeInstruction(SpvOpConvertUToF, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001178 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001179 }
1180 return result;
1181}
1182
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001183SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001184 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001185 SkASSERT(c.arguments().size() == 1);
1186 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001187 SkASSERT(constructorType.isSigned());
1188 SkASSERT(argType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001189 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001190 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001191 if (argType.isFloat()) {
1192 this->writeInstruction(SpvOpConvertFToS, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001193 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001194 }
1195 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001196 SkASSERT(argType.isUnsigned());
1197 this->writeInstruction(SpvOpBitcast, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001198 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001199 }
1200 return result;
1201}
1202
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001203SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001204 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001205 SkASSERT(c.arguments().size() == 1);
1206 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001207 SkASSERT(constructorType.isUnsigned());
1208 SkASSERT(argType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001209 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001210 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001211 if (argType.isFloat()) {
1212 this->writeInstruction(SpvOpConvertFToU, this->getType(constructorType), result, parameter,
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001213 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001214 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001215 SkASSERT(argType.isSigned());
1216 this->writeInstruction(SpvOpBitcast, this->getType(constructorType), result, parameter,
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001217 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001218 }
1219 return result;
1220}
1221
Ethan Nicholas84645e32017-02-09 13:57:14 -05001222void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001223 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001224 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001225 SpvId zeroId = this->writeFloatLiteral(zero);
1226 std::vector<SpvId> columnIds;
1227 for (int column = 0; column < type.columns(); column++) {
1228 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1229 out);
1230 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1231 out);
1232 SpvId columnId = this->nextId();
1233 this->writeWord(columnId, out);
1234 columnIds.push_back(columnId);
1235 for (int row = 0; row < type.columns(); row++) {
1236 this->writeWord(row == column ? diagonal : zeroId, out);
1237 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001238 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001239 }
1240 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1241 out);
1242 this->writeWord(this->getType(type), out);
1243 this->writeWord(id, out);
John Stilesf621e232020-08-25 13:33:02 -04001244 for (SpvId columnId : columnIds) {
1245 this->writeWord(columnId, out);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001246 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001247 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001248}
1249
1250void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001251 const Type& dstType, OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05001252 SkASSERT(srcType.isMatrix());
1253 SkASSERT(dstType.isMatrix());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001254 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001255 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1256 srcType.rows(),
1257 1));
1258 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1259 dstType.rows(),
1260 1));
1261 SpvId zeroId;
1262 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001263 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001264 zeroId = this->writeFloatLiteral(zero);
1265 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001266 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001267 zeroId = this->writeIntLiteral(zero);
1268 } else {
1269 ABORT("unsupported matrix component type");
1270 }
1271 SpvId zeroColumn = 0;
1272 SpvId columns[4];
1273 for (int i = 0; i < dstType.columns(); i++) {
1274 if (i < srcType.columns()) {
1275 // we're still inside the src matrix, copy the column
1276 SpvId srcColumn = this->nextId();
1277 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001278 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001279 SpvId dstColumn;
1280 if (srcType.rows() == dstType.rows()) {
1281 // columns are equal size, don't need to do anything
1282 dstColumn = srcColumn;
1283 }
1284 else if (dstType.rows() > srcType.rows()) {
1285 // dst column is bigger, need to zero-pad it
1286 dstColumn = this->nextId();
1287 int delta = dstType.rows() - srcType.rows();
1288 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1289 this->writeWord(dstColumnType, out);
1290 this->writeWord(dstColumn, out);
1291 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001292 for (int j = 0; j < delta; ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001293 this->writeWord(zeroId, out);
1294 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001295 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001296 }
1297 else {
1298 // dst column is smaller, need to swizzle the src column
1299 dstColumn = this->nextId();
1300 int count = dstType.rows();
1301 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1302 this->writeWord(dstColumnType, out);
1303 this->writeWord(dstColumn, out);
1304 this->writeWord(srcColumn, out);
1305 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001306 for (int j = 0; j < count; j++) {
1307 this->writeWord(j, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001308 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001309 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001310 }
1311 columns[i] = dstColumn;
1312 } else {
1313 // we're past the end of the src matrix, need a vector of zeroes
1314 if (!zeroColumn) {
1315 zeroColumn = this->nextId();
1316 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1317 this->writeWord(dstColumnType, out);
1318 this->writeWord(zeroColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001319 for (int j = 0; j < dstType.rows(); ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001320 this->writeWord(zeroId, out);
1321 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001322 this->writePrecisionModifier(dstType, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001323 }
1324 columns[i] = zeroColumn;
1325 }
1326 }
1327 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1328 this->writeWord(this->getType(dstType), out);
1329 this->writeWord(id, out);
1330 for (int i = 0; i < dstType.columns(); i++) {
1331 this->writeWord(columns[i], out);
1332 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001333 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001334}
1335
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001336void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1337 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001338 std::vector<SpvId>* columnIds,
1339 int* currentCount, int rows, SpvId entry,
1340 OutputStream& out) {
1341 SkASSERT(*currentCount < rows);
1342 ++(*currentCount);
1343 currentColumn->push_back(entry);
1344 if (*currentCount == rows) {
1345 *currentCount = 0;
1346 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1347 this->writeWord(columnType, out);
1348 SpvId columnId = this->nextId();
1349 this->writeWord(columnId, out);
1350 columnIds->push_back(columnId);
1351 for (SpvId id : *currentColumn) {
1352 this->writeWord(id, out);
1353 }
1354 currentColumn->clear();
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001355 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001356 }
1357}
1358
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001359SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001360 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001361 SkASSERT(type.isMatrix());
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001362 SkASSERT(c.arguments().size() > 0);
1363 const Type& arg0Type = c.arguments()[0]->type();
ethannicholasb3058bd2016-07-01 08:22:01 -07001364 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1365 // an instruction
1366 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001367 for (size_t i = 0; i < c.arguments().size(); i++) {
1368 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001369 }
1370 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001371 int rows = type.rows();
1372 int columns = type.columns();
John Stiles9aeed132020-11-24 17:36:06 -05001373 if (arguments.size() == 1 && arg0Type.isScalar()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001374 this->writeUniformScaleMatrix(result, arguments[0], type, out);
John Stiles9aeed132020-11-24 17:36:06 -05001375 } else if (arguments.size() == 1 && arg0Type.isMatrix()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001376 this->writeMatrixCopy(result, arguments[0], arg0Type, type, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001377 } else if (arguments.size() == 1 &&
John Stiles9aeed132020-11-24 17:36:06 -05001378 arg0Type.isVector()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001379 SkASSERT(type.rows() == 2 && type.columns() == 2);
1380 SkASSERT(arg0Type.columns() == 4);
1381 SpvId componentType = this->getType(type.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001382 SpvId v[4];
1383 for (int i = 0; i < 4; ++i) {
1384 v[i] = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001385 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i,
1386 out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001387 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001388 SpvId columnType = this->getType(type.componentType().toCompound(fContext, 2, 1));
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001389 SpvId column1 = this->nextId();
1390 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1391 SpvId column2 = this->nextId();
1392 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001393 this->writeInstruction(SpvOpCompositeConstruct, this->getType(type), result, column1,
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001394 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001395 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001396 SpvId columnType = this->getType(type.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001397 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001398 // ids of vectors and scalars we have written to the current column so far
1399 std::vector<SpvId> currentColumn;
1400 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001401 int currentCount = 0;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001402 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001403 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001404 const Type& argType = c.arguments()[i]->type();
John Stiles9aeed132020-11-24 17:36:06 -05001405 if (currentCount == 0 && argType.isVector() &&
Ethan Nicholas30d30222020-09-11 12:27:26 -04001406 argType.columns() == type.rows()) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001407 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001408 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001409 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001410 if (argType.columns() == 1) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001411 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1412 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001413 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001414 SpvId componentType = this->getType(argType.componentType());
1415 for (int j = 0; j < argType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001416 SpvId swizzle = this->nextId();
1417 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1418 arguments[i], j, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001419 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1420 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001421 }
1422 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001423 }
1424 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001425 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001426 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001427 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001428 this->writeWord(result, out);
1429 for (SpvId id : columnIds) {
1430 this->writeWord(id, out);
1431 }
1432 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001433 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001434 return result;
1435}
1436
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001437SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001438 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001439 SkASSERT(type.isVector());
Brian Osmanb6b95732020-06-30 11:44:27 -04001440 if (c.isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001441 return this->writeConstantVector(c);
1442 }
1443 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1444 // an instruction
1445 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001446 for (size_t i = 0; i < c.arguments().size(); i++) {
1447 const Type& argType = c.arguments()[i]->type();
John Stiles9aeed132020-11-24 17:36:06 -05001448 if (argType.isVector()) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001449 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1450 // extract the components and convert them in that case manually. On top of that,
1451 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1452 // doesn't handle vector arguments at all, so we always extract vector components and
1453 // pass them into OpCreateComposite individually.
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001454 SpvId vec = this->writeExpression(*c.arguments()[i], out);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001455 SpvOp_ op = SpvOpUndef;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001456 const Type& src = argType.componentType();
1457 const Type& dst = type.componentType();
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001458 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1459 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001460 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001461 return vec;
1462 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001463 } else if (src == *fContext.fInt_Type ||
1464 src == *fContext.fShort_Type ||
1465 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001466 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001467 } else if (src == *fContext.fUInt_Type ||
1468 src == *fContext.fUShort_Type ||
1469 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001470 op = SpvOpConvertUToF;
1471 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001472 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001473 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001474 } else if (dst == *fContext.fInt_Type ||
1475 dst == *fContext.fShort_Type ||
1476 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001477 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1478 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001479 } else if (src == *fContext.fInt_Type ||
1480 src == *fContext.fShort_Type ||
1481 src == *fContext.fByte_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001482 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001483 return vec;
1484 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001485 } else if (src == *fContext.fUInt_Type ||
1486 src == *fContext.fUShort_Type ||
1487 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001488 op = SpvOpBitcast;
1489 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001490 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001491 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001492 } else if (dst == *fContext.fUInt_Type ||
1493 dst == *fContext.fUShort_Type ||
1494 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001495 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1496 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001497 } else if (src == *fContext.fInt_Type ||
1498 src == *fContext.fShort_Type ||
1499 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001500 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001501 } else if (src == *fContext.fUInt_Type ||
1502 src == *fContext.fUShort_Type ||
1503 src == *fContext.fUByte_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001504 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001505 return vec;
1506 }
1507 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001508 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001509 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001510 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001511 for (int j = 0; j < argType.columns(); j++) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001512 SpvId swizzle = this->nextId();
1513 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1514 out);
1515 if (op != SpvOpUndef) {
1516 SpvId cast = this->nextId();
1517 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1518 arguments.push_back(cast);
1519 } else {
1520 arguments.push_back(swizzle);
1521 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001522 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001523 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001524 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001525 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001526 }
1527 SpvId result = this->nextId();
John Stiles9aeed132020-11-24 17:36:06 -05001528 if (arguments.size() == 1 && c.arguments()[0]->type().isScalar()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001529 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(), out);
1530 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001531 this->writeWord(result, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001532 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001533 this->writeWord(arguments[0], out);
1534 }
1535 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001536 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001537 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001538 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001539 this->writeWord(result, out);
1540 for (SpvId id : arguments) {
1541 this->writeWord(id, out);
1542 }
1543 }
1544 return result;
1545}
1546
Ethan Nicholasbd553222017-07-18 15:54:59 -04001547SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001548 const Type& type = c.type();
John Stilesc0c51062020-12-03 17:16:29 -05001549 SkASSERT(type.isArray());
Ethan Nicholasbd553222017-07-18 15:54:59 -04001550 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1551 // an instruction
1552 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001553 for (size_t i = 0; i < c.arguments().size(); i++) {
1554 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholasbd553222017-07-18 15:54:59 -04001555 }
1556 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001557 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.arguments().size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001558 this->writeWord(this->getType(type), out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001559 this->writeWord(result, out);
1560 for (SpvId id : arguments) {
1561 this->writeWord(id, out);
1562 }
1563 return result;
1564}
1565
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001566SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001567 const Type& type = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001568 if (c.arguments().size() == 1 &&
1569 this->getActualType(type) == this->getActualType(c.arguments()[0]->type())) {
1570 return this->writeExpression(*c.arguments()[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001571 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001572 if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001573 return this->writeFloatConstructor(c, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001574 } else if (type == *fContext.fInt_Type ||
1575 type == *fContext.fShort_Type ||
1576 type == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001577 return this->writeIntConstructor(c, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001578 } else if (type == *fContext.fUInt_Type ||
1579 type == *fContext.fUShort_Type ||
1580 type == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001581 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001582 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001583 switch (type.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001584 case Type::TypeKind::kVector:
ethannicholasb3058bd2016-07-01 08:22:01 -07001585 return this->writeVectorConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001586 case Type::TypeKind::kMatrix:
ethannicholasb3058bd2016-07-01 08:22:01 -07001587 return this->writeMatrixConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001588 case Type::TypeKind::kArray:
Ethan Nicholasbd553222017-07-18 15:54:59 -04001589 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001590 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001591#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07001592 ABORT("unsupported constructor: %s", c.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001593#endif
1594 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001595 }
1596}
1597
1598SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1599 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001600 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001601 return SpvStorageClassInput;
1602 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001603 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001604 return SpvStorageClassOutput;
1605 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001606 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001607 return SpvStorageClassPushConstant;
1608 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001609 return SpvStorageClassUniform;
1610 } else {
1611 return SpvStorageClassFunction;
1612 }
1613}
1614
ethannicholasf789b382016-08-03 12:43:36 -07001615SpvStorageClass_ get_storage_class(const Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001616 switch (expr.kind()) {
1617 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -04001618 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001619 if (var.storage() != Variable::Storage::kGlobal) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001620 return SpvStorageClassFunction;
1621 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001622 SpvStorageClass_ result = get_storage_class(var.modifiers());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001623 if (result == SpvStorageClassFunction) {
1624 result = SpvStorageClassPrivate;
1625 }
1626 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001627 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001628 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001629 return get_storage_class(*expr.as<FieldAccess>().base());
Ethan Nicholase6592142020-09-08 10:22:09 -04001630 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001631 return get_storage_class(*expr.as<IndexExpression>().base());
ethannicholasb3058bd2016-07-01 08:22:01 -07001632 default:
1633 return SpvStorageClassFunction;
1634 }
1635}
1636
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001637std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001638 std::vector<SpvId> chain;
Ethan Nicholase6592142020-09-08 10:22:09 -04001639 switch (expr.kind()) {
1640 case Expression::Kind::kIndex: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001641 IndexExpression& indexExpr = (IndexExpression&) expr;
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001642 chain = this->getAccessChain(*indexExpr.base(), out);
1643 chain.push_back(this->writeExpression(*indexExpr.index(), out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001644 break;
1645 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001646 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001647 FieldAccess& fieldExpr = (FieldAccess&) expr;
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001648 chain = this->getAccessChain(*fieldExpr.base(), out);
1649 IntLiteral index(fContext, -1, fieldExpr.fieldIndex());
ethannicholasb3058bd2016-07-01 08:22:01 -07001650 chain.push_back(this->writeIntLiteral(index));
1651 break;
1652 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001653 default: {
1654 SpvId id = this->getLValue(expr, out)->getPointer();
1655 SkASSERT(id != 0);
1656 chain.push_back(id);
1657 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001658 }
1659 return chain;
1660}
1661
1662class PointerLValue : public SPIRVCodeGenerator::LValue {
1663public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001664 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1665 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001666 : fGen(gen)
1667 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001668 , fType(type)
1669 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001670
John Stiles1cf2c8d2020-08-13 22:58:04 -04001671 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001672 return fPointer;
1673 }
1674
John Stiles1cf2c8d2020-08-13 22:58:04 -04001675 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001676 SpvId result = fGen.nextId();
1677 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001678 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001679 return result;
1680 }
1681
John Stiles1cf2c8d2020-08-13 22:58:04 -04001682 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001683 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1684 }
1685
1686private:
1687 SPIRVCodeGenerator& fGen;
1688 const SpvId fPointer;
1689 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001690 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001691};
1692
1693class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1694public:
John Stiles750109b2020-10-30 13:45:46 -04001695 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const ComponentArray& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001696 const Type& baseType, const Type& swizzleType,
1697 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001698 : fGen(gen)
1699 , fVecPointer(vecPointer)
1700 , fComponents(components)
1701 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001702 , fSwizzleType(swizzleType)
1703 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001704
John Stiles1cf2c8d2020-08-13 22:58:04 -04001705 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001706 return 0;
1707 }
1708
John Stiles1cf2c8d2020-08-13 22:58:04 -04001709 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001710 SpvId base = fGen.nextId();
1711 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001712 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001713 SpvId result = fGen.nextId();
1714 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1715 fGen.writeWord(fGen.getType(fSwizzleType), out);
1716 fGen.writeWord(result, out);
1717 fGen.writeWord(base, out);
1718 fGen.writeWord(base, out);
1719 for (int component : fComponents) {
1720 fGen.writeWord(component, out);
1721 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001722 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001723 return result;
1724 }
1725
John Stiles1cf2c8d2020-08-13 22:58:04 -04001726 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001727 // use OpVectorShuffle to mix and match the vector components. We effectively create
1728 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001729 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001730 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001731 // float3L = ...;
1732 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001733 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001734 // 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 -07001735 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1736 // (3, 1, 4).
1737 SpvId base = fGen.nextId();
1738 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1739 SpvId shuffle = fGen.nextId();
1740 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1741 fGen.writeWord(fGen.getType(fBaseType), out);
1742 fGen.writeWord(shuffle, out);
1743 fGen.writeWord(base, out);
1744 fGen.writeWord(value, out);
1745 for (int i = 0; i < fBaseType.columns(); i++) {
1746 // current offset into the virtual vector, defaults to pulling the unmodified
1747 // value from the left side
1748 int offset = i;
1749 // check to see if we are writing this component
1750 for (size_t j = 0; j < fComponents.size(); j++) {
1751 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001752 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001753 // the correct component of the right side instead of preserving the
1754 // value from the left
1755 offset = (int) (j + fBaseType.columns());
1756 break;
1757 }
1758 }
1759 fGen.writeWord(offset, out);
1760 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001761 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001762 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1763 }
1764
1765private:
1766 SPIRVCodeGenerator& fGen;
1767 const SpvId fVecPointer;
John Stiles750109b2020-10-30 13:45:46 -04001768 const ComponentArray& fComponents;
ethannicholasb3058bd2016-07-01 08:22:01 -07001769 const Type& fBaseType;
1770 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001771 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001772};
1773
Greg Daniel64773e62016-11-22 09:44:03 -05001774std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001775 OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001776 const Type& type = expr.type();
1777 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
Ethan Nicholase6592142020-09-08 10:22:09 -04001778 switch (expr.kind()) {
1779 case Expression::Kind::kVariableReference: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001780 SpvId typeId;
Ethan Nicholas78686922020-10-08 06:46:27 -04001781 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001782 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
John Stilesad2d4942020-12-11 16:55:58 -05001783 typeId = this->getType(*Type::MakeArrayType("sk_in", var.type().componentType(),
1784 fSkInCount));
Ethan Nicholas5226b772018-05-03 16:20:41 -04001785 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001786 typeId = this->getType(type);
Ethan Nicholas5226b772018-05-03 16:20:41 -04001787 }
ethannicholasd598f792016-07-25 10:08:54 -07001788 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001789 SkASSERT(entry != fVariableMap.end());
John Stiles5570c512020-11-19 17:58:07 -05001790 return std::make_unique<PointerLValue>(*this, entry->second, typeId, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001791 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001792 case Expression::Kind::kIndex: // fall through
1793 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001794 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1795 SpvId member = this->nextId();
1796 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001797 this->writeWord(this->getPointerType(type, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001798 this->writeWord(member, out);
1799 for (SpvId idx : chain) {
1800 this->writeWord(idx, out);
1801 }
John Stiles5570c512020-11-19 17:58:07 -05001802 return std::make_unique<PointerLValue>(*this, member, this->getType(type), precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001803 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001804 case Expression::Kind::kSwizzle: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001805 Swizzle& swizzle = (Swizzle&) expr;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001806 size_t count = swizzle.components().size();
1807 SpvId base = this->getLValue(*swizzle.base(), out)->getPointer();
John Stiles5570c512020-11-19 17:58:07 -05001808 if (!base) {
1809 fErrors.error(swizzle.fOffset, "unable to retrieve lvalue from swizzle");
1810 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001811 if (count == 1) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001812 IntLiteral index(fContext, -1, swizzle.components()[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001813 SpvId member = this->nextId();
1814 this->writeInstruction(SpvOpAccessChain,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001815 this->getPointerType(type,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001816 get_storage_class(*swizzle.base())),
Greg Daniel64773e62016-11-22 09:44:03 -05001817 member,
1818 base,
1819 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001820 out);
John Stiles5570c512020-11-19 17:58:07 -05001821 return std::make_unique<PointerLValue>(*this, member, this->getType(type),
1822 precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001823 } else {
John Stiles5570c512020-11-19 17:58:07 -05001824 return std::make_unique<SwizzleLValue>(*this, base, swizzle.components(),
1825 swizzle.base()->type(), type, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001826 }
1827 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001828 case Expression::Kind::kTernary: {
Ethan Nicholasa583b812018-01-18 13:32:11 -05001829 TernaryExpression& t = (TernaryExpression&) expr;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001830 SpvId test = this->writeExpression(*t.test(), out);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001831 SpvId end = this->nextId();
1832 SpvId ifTrueLabel = this->nextId();
1833 SpvId ifFalseLabel = this->nextId();
1834 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1835 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1836 this->writeLabel(ifTrueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04001837 SpvId ifTrue = this->getLValue(*t.ifTrue(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001838 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001839 this->writeInstruction(SpvOpBranch, end, out);
1840 ifTrueLabel = fCurrentBlock;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001841 SpvId ifFalse = this->getLValue(*t.ifFalse(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001842 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001843 ifFalseLabel = fCurrentBlock;
1844 this->writeInstruction(SpvOpBranch, end, out);
1845 SpvId result = this->nextId();
1846 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1847 ifTrueLabel, ifFalse, ifFalseLabel, out);
John Stiles5570c512020-11-19 17:58:07 -05001848 return std::make_unique<PointerLValue>(*this, result, this->getType(type), precision);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001849 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001850 default: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001851 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001852 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001853 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1854 // caught by IRGenerator
1855 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001856 SpvId pointerType = this->getPointerType(type, SpvStorageClassFunction);
1857 this->writeInstruction(SpvOpVariable, pointerType, result, SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001858 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001859 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
John Stiles5570c512020-11-19 17:58:07 -05001860 return std::make_unique<PointerLValue>(*this, result, this->getType(type), precision);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001861 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001862 }
1863}
1864
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001865SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001866 SpvId result = this->nextId();
Ethan Nicholas78686922020-10-08 06:46:27 -04001867 auto entry = fVariableMap.find(ref.variable());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001868 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001869 SpvId var = entry->second;
Ethan Nicholas78686922020-10-08 06:46:27 -04001870 this->writeInstruction(SpvOpLoad, this->getType(ref.variable()->type()), result, var, out);
1871 this->writePrecisionModifier(ref.variable()->type(), result);
1872 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
Brian Osmane38bedd2020-12-21 11:51:54 -05001873 fProgram.fSettings.fFlipY) {
Greg Daniela85e4bf2020-06-17 16:32:45 -04001874 // The x component never changes, so just grab it
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001875 SpvId xId = this->nextId();
1876 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1877 result, 0, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001878
1879 // Calculate the y component which may need to be flipped
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001880 SpvId rawYId = this->nextId();
1881 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1882 result, 1, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001883 SpvId flippedYId = 0;
1884 if (fProgram.fSettings.fFlipY) {
1885 // need to remap to a top-left coordinate system
1886 if (fRTHeightStructId == (SpvId)-1) {
1887 // height variable hasn't been written yet
Greg Daniela85e4bf2020-06-17 16:32:45 -04001888 SkASSERT(fRTHeightFieldIndex == (SpvId)-1);
1889 std::vector<Type::Field> fields;
John Stiles5570c512020-11-19 17:58:07 -05001890 if (fProgram.fSettings.fRTHeightOffset < 0) {
1891 fErrors.error(ref.fOffset, "RTHeightOffset is negative");
1892 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001893 fields.emplace_back(
1894 Modifiers(Layout(0, -1, fProgram.fSettings.fRTHeightOffset, -1, -1, -1, -1,
1895 -1, Layout::Format::kUnspecified,
1896 Layout::kUnspecified_Primitive, 1, -1, "", "",
1897 Layout::kNo_Key, Layout::CType::kDefault),
1898 0),
1899 SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1900 StringFragment name("sksl_synthetic_uniforms");
John Stilesad2d4942020-12-11 16:55:58 -05001901 std::unique_ptr<Type> intfStruct = Type::MakeStructType(/*offset=*/-1, name,
1902 fields);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001903 int binding = fProgram.fSettings.fRTHeightBinding;
John Stiles5570c512020-11-19 17:58:07 -05001904 if (binding == -1) {
1905 fErrors.error(ref.fOffset, "layout(binding=...) is required in SPIR-V");
1906 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001907 int set = fProgram.fSettings.fRTHeightSet;
John Stiles5570c512020-11-19 17:58:07 -05001908 if (set == -1) {
1909 fErrors.error(ref.fOffset, "layout(set=...) is required in SPIR-V");
1910 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001911 Layout layout(0, -1, -1, binding, -1, set, -1, -1, Layout::Format::kUnspecified,
1912 Layout::kUnspecified_Primitive, -1, -1, "", "", Layout::kNo_Key,
1913 Layout::CType::kDefault);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001914 Modifiers modifiers(layout, Modifiers::kUniform_Flag);
John Stiles3ae071e2020-08-05 15:29:29 -04001915 const Variable* intfVar = fSynthetics.takeOwnershipOfSymbol(
1916 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -05001917 fProgram.fModifiers->addToPool(modifiers),
John Stiles3ae071e2020-08-05 15:29:29 -04001918 name,
John Stilesad2d4942020-12-11 16:55:58 -05001919 intfStruct.get(),
Brian Osman3887a012020-09-30 13:22:27 -04001920 /*builtin=*/false,
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001921 Variable::Storage::kGlobal));
John Stilesd39aec02020-12-03 10:42:26 -05001922 InterfaceBlock intf(/*offset=*/-1, intfVar, name,
1923 /*instanceName=*/"", /*arraySize=*/0,
John Stiles7c3515b2020-10-16 18:38:39 -04001924 std::make_shared<SymbolTable>(&fErrors, /*builtin=*/false));
Stephen White88574972020-06-23 19:09:29 -04001925
1926 fRTHeightStructId = this->writeInterfaceBlock(intf, false);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001927 fRTHeightFieldIndex = 0;
Jim Van Verthf3ec9832020-10-21 16:09:57 -04001928 fRTHeightStorageClass = SpvStorageClassUniform;
Greg Daniela85e4bf2020-06-17 16:32:45 -04001929 }
1930 SkASSERT(fRTHeightFieldIndex != (SpvId)-1);
1931
1932 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1933 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1934 SpvId heightPtr = this->nextId();
1935 this->writeOpCode(SpvOpAccessChain, 5, out);
Jim Van Verthf3ec9832020-10-21 16:09:57 -04001936 this->writeWord(this->getPointerType(*fContext.fFloat_Type, fRTHeightStorageClass),
Greg Daniela85e4bf2020-06-17 16:32:45 -04001937 out);
1938 this->writeWord(heightPtr, out);
1939 this->writeWord(fRTHeightStructId, out);
1940 this->writeWord(fieldIndexId, out);
1941 SpvId heightRead = this->nextId();
1942 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1943 heightPtr, out);
1944
1945 flippedYId = this->nextId();
1946 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
1947 heightRead, rawYId, out);
1948 }
1949
1950 // The z component will always be zero so we just get an id to the 0 literal
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001951 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001952 SpvId zeroId = writeFloatLiteral(zero);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001953
Brian Osmane38bedd2020-12-21 11:51:54 -05001954 // Calculate the w component
Greg Daniela85e4bf2020-06-17 16:32:45 -04001955 SpvId rawWId = this->nextId();
1956 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawWId,
Ethan Nicholas20798e52018-12-04 12:30:50 -05001957 result, 3, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001958
1959 // Fill in the new fragcoord with the components from above
1960 SpvId adjusted = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001961 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001962 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001963 this->writeWord(adjusted, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001964 this->writeWord(xId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001965 if (fProgram.fSettings.fFlipY) {
1966 this->writeWord(flippedYId, out);
1967 } else {
1968 this->writeWord(rawYId, out);
1969 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001970 this->writeWord(zeroId, out);
Brian Osmane38bedd2020-12-21 11:51:54 -05001971 this->writeWord(rawWId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001972
1973 return adjusted;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001974 }
Ethan Nicholas78686922020-10-08 06:46:27 -04001975 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
Chris Daltonb91c4662018-08-01 10:46:22 -06001976 !fProgram.fSettings.fFlipY) {
1977 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1978 // the default convention of "counter-clockwise face is front".
1979 SpvId inverse = this->nextId();
1980 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1981 result, out);
1982 return inverse;
1983 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001984 return result;
1985}
1986
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001987SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05001988 if (expr.base()->type().isVector()) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001989 SpvId base = this->writeExpression(*expr.base(), out);
1990 SpvId index = this->writeExpression(*expr.index(), out);
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001991 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001992 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.type()), result, base,
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001993 index, out);
1994 return result;
1995 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001996 return getLValue(expr, out)->load(out);
1997}
1998
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001999SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002000 return getLValue(f, out)->load(out);
2001}
2002
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002003SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002004 SpvId base = this->writeExpression(*swizzle.base(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002005 SpvId result = this->nextId();
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002006 size_t count = swizzle.components().size();
ethannicholasb3058bd2016-07-01 08:22:01 -07002007 if (count == 1) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002008 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.type()), result, base,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002009 swizzle.components()[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002010 } else {
2011 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002012 this->writeWord(this->getType(swizzle.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002013 this->writeWord(result, out);
2014 this->writeWord(base, out);
Brian Osman25647672020-09-15 15:16:56 -04002015 this->writeWord(base, out);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002016 for (int component : swizzle.components()) {
Brian Osman25647672020-09-15 15:16:56 -04002017 this->writeWord(component, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002018 }
2019 }
2020 return result;
2021}
2022
Greg Daniel64773e62016-11-22 09:44:03 -05002023SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
2024 const Type& operandType, SpvId lhs,
2025 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002026 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002027 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002028 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002029 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002030 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002031 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002032 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002033 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
John Stiles123501f2020-12-09 10:08:13 -05002034 } else if (is_bool(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002035 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002036 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07002037 } else {
John Stiles123501f2020-12-09 10:08:13 -05002038 fErrors.error(operandType.fOffset,
2039 "unsupported operand for binary expression: " + operandType.description());
2040 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002041 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04002042 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002043 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
2044 fDecorationBuffer);
2045 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002046 return result;
2047}
2048
Ethan Nicholas48e24052018-03-14 13:51:39 -04002049SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
2050 OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05002051 if (operandType.isVector()) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002052 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04002053 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002054 return result;
2055 }
2056 return id;
2057}
2058
Ethan Nicholas68990be2017-07-13 09:36:52 -04002059SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
2060 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002061 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04002062 OutputStream& out) {
2063 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
John Stiles9aeed132020-11-24 17:36:06 -05002064 SkASSERT(operandType.isMatrix());
Ethan Nicholas0df21132018-07-10 09:37:51 -04002065 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2066 operandType.rows(),
2067 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04002068 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002069 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04002070 1));
2071 SpvId boolType = this->getType(*fContext.fBool_Type);
2072 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04002073 for (int i = 0; i < operandType.columns(); i++) {
2074 SpvId columnL = this->nextId();
2075 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2076 SpvId columnR = this->nextId();
2077 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002078 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002079 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
2080 SpvId merge = this->nextId();
2081 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002082 if (result != 0) {
2083 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002084 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002085 result = next;
2086 }
2087 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002088 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04002089 }
2090 }
2091 return result;
2092}
2093
Ethan Nicholas0df21132018-07-10 09:37:51 -04002094SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
2095 SpvId rhs, SpvOp_ floatOperator,
2096 SpvOp_ intOperator,
2097 OutputStream& out) {
2098 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
John Stiles9aeed132020-11-24 17:36:06 -05002099 SkASSERT(operandType.isMatrix());
Ethan Nicholas0df21132018-07-10 09:37:51 -04002100 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2101 operandType.rows(),
2102 1));
2103 SpvId columns[4];
2104 for (int i = 0; i < operandType.columns(); i++) {
2105 SpvId columnL = this->nextId();
2106 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2107 SpvId columnR = this->nextId();
2108 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2109 columns[i] = this->nextId();
2110 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2111 }
2112 SpvId result = this->nextId();
2113 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2114 this->writeWord(this->getType(operandType), out);
2115 this->writeWord(result, out);
2116 for (int i = 0; i < operandType.columns(); i++) {
2117 this->writeWord(columns[i], out);
2118 }
2119 return result;
2120}
2121
Ethan Nicholas49465b42019-04-17 12:22:21 -04002122std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2123 if (type.isInteger()) {
2124 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002125 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002126 else if (type.isFloat()) {
2127 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002128 } else {
Ethan Nicholase2c49992020-10-05 11:49:11 -04002129 ABORT("math is unsupported on type '%s'", String(type.name()).c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002130 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002131}
2132
2133SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Token::Kind op,
2134 const Type& rightType, SpvId rhs,
2135 const Type& resultType, OutputStream& out) {
John Stilesd0614f22020-12-09 11:11:41 -05002136 // The comma operator ignores the type of the left-hand side entirely.
2137 if (op == Token::Kind::TK_COMMA) {
2138 return rhs;
2139 }
Ethan Nicholas48e24052018-03-14 13:51:39 -04002140 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002141 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002142 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2143 // handling in SPIR-V
Ethan Nicholas49465b42019-04-17 12:22:21 -04002144 if (this->getActualType(leftType) != this->getActualType(rightType)) {
John Stiles9aeed132020-11-24 17:36:06 -05002145 if (leftType.isVector() && rightType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002146 if (op == Token::Kind::TK_SLASH) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002147 SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
2148 SpvId inverse = this->nextId();
2149 this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
2150 rhs = inverse;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002151 op = Token::Kind::TK_STAR;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002152 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002153 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002154 SpvId result = this->nextId();
2155 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2156 result, lhs, rhs, out);
2157 return result;
2158 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002159 // promote number to vector
2160 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002161 const Type& vecType = leftType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002162 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2163 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002164 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002165 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002166 this->writeWord(rhs, out);
2167 }
2168 rhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002169 operandType = &leftType;
John Stiles9aeed132020-11-24 17:36:06 -05002170 } else if (rightType.isVector() && leftType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002171 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002172 SpvId result = this->nextId();
2173 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2174 result, rhs, lhs, out);
2175 return result;
2176 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002177 // promote number to vector
2178 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002179 const Type& vecType = rightType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002180 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2181 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002182 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002183 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002184 this->writeWord(lhs, out);
2185 }
2186 lhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002187 operandType = &rightType;
John Stiles9aeed132020-11-24 17:36:06 -05002188 } else if (leftType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002189 SpvOp_ spvop;
John Stiles9aeed132020-11-24 17:36:06 -05002190 if (rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002191 spvop = SpvOpMatrixTimesMatrix;
John Stiles9aeed132020-11-24 17:36:06 -05002192 } else if (rightType.isVector()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002193 spvop = SpvOpMatrixTimesVector;
ethannicholasb3058bd2016-07-01 08:22:01 -07002194 } else {
John Stiles9aeed132020-11-24 17:36:06 -05002195 SkASSERT(rightType.isScalar());
Ethan Nicholas49465b42019-04-17 12:22:21 -04002196 spvop = SpvOpMatrixTimesScalar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002197 }
2198 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002199 this->writeInstruction(spvop, this->getType(resultType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002200 return result;
John Stiles9aeed132020-11-24 17:36:06 -05002201 } else if (rightType.isMatrix()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002202 SpvId result = this->nextId();
John Stiles9aeed132020-11-24 17:36:06 -05002203 if (leftType.isVector()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002204 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(resultType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002205 lhs, rhs, out);
2206 } else {
John Stiles9aeed132020-11-24 17:36:06 -05002207 SkASSERT(leftType.isScalar());
Ethan Nicholas49465b42019-04-17 12:22:21 -04002208 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(resultType), result,
2209 rhs, lhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002210 }
2211 return result;
2212 } else {
John Stilesd8ca6b62020-11-23 14:28:36 -05002213 fErrors.error(leftType.fOffset, "unsupported mixed-type expression");
Ethan Nicholas49465b42019-04-17 12:22:21 -04002214 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002215 }
2216 } else {
John Stiles2d4f9592020-10-30 10:29:12 -04002217 operandType = &this->getActualType(leftType);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002218 SkASSERT(*operandType == this->getActualType(rightType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002219 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002220 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002221 case Token::Kind::TK_EQEQ: {
John Stiles9aeed132020-11-24 17:36:06 -05002222 if (operandType->isMatrix()) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002223 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002224 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002225 }
John Stiles4a7dc462020-11-25 11:08:08 -05002226 SkASSERT(resultType.isBoolean());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002227 const Type* tmpType;
John Stiles9aeed132020-11-24 17:36:06 -05002228 if (operandType->isVector()) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002229 tmpType = &fContext.fBool_Type->toCompound(fContext,
2230 operandType->columns(),
2231 operandType->rows());
2232 } else {
2233 tmpType = &resultType;
2234 }
2235 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002236 SpvOpFOrdEqual, SpvOpIEqual,
2237 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002238 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002239 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002240 case Token::Kind::TK_NEQ:
John Stiles9aeed132020-11-24 17:36:06 -05002241 if (operandType->isMatrix()) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002242 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002243 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002244 }
John Stiles4a7dc462020-11-25 11:08:08 -05002245 [[fallthrough]];
2246 case Token::Kind::TK_LOGICALXOR:
2247 SkASSERT(resultType.isBoolean());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002248 const Type* tmpType;
John Stiles9aeed132020-11-24 17:36:06 -05002249 if (operandType->isVector()) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002250 tmpType = &fContext.fBool_Type->toCompound(fContext,
2251 operandType->columns(),
2252 operandType->rows());
2253 } else {
2254 tmpType = &resultType;
2255 }
2256 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002257 SpvOpFOrdNotEqual, SpvOpINotEqual,
2258 SpvOpINotEqual, SpvOpLogicalNotEqual,
2259 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002260 *operandType, SpvOpAny, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002261 case Token::Kind::TK_GT:
John Stiles4a7dc462020-11-25 11:08:08 -05002262 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002263 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2264 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002265 SpvOpUGreaterThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002266 case Token::Kind::TK_LT:
John Stiles4a7dc462020-11-25 11:08:08 -05002267 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002268 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002269 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002270 case Token::Kind::TK_GTEQ:
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 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002274 SpvOpUGreaterThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002275 case Token::Kind::TK_LTEQ:
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,
2278 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002279 SpvOpULessThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002280 case Token::Kind::TK_PLUS:
John Stiles9aeed132020-11-24 17:36:06 -05002281 if (leftType.isMatrix() && rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002282 SkASSERT(leftType == rightType);
2283 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002284 SpvOpFAdd, SpvOpIAdd, out);
2285 }
Greg Daniel64773e62016-11-22 09:44:03 -05002286 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002287 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002288 case Token::Kind::TK_MINUS:
John Stiles9aeed132020-11-24 17:36:06 -05002289 if (leftType.isMatrix() && rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002290 SkASSERT(leftType == rightType);
2291 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002292 SpvOpFSub, SpvOpISub, out);
2293 }
Greg Daniel64773e62016-11-22 09:44:03 -05002294 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002295 SpvOpISub, SpvOpISub, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002296 case Token::Kind::TK_STAR:
John Stiles9aeed132020-11-24 17:36:06 -05002297 if (leftType.isMatrix() && rightType.isMatrix()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002298 // matrix multiply
2299 SpvId result = this->nextId();
2300 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2301 lhs, rhs, out);
2302 return result;
2303 }
Greg Daniel64773e62016-11-22 09:44:03 -05002304 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002305 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002306 case Token::Kind::TK_SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002307 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002308 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002309 case Token::Kind::TK_PERCENT:
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002310 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2311 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002312 case Token::Kind::TK_SHL:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002313 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2314 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2315 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002316 case Token::Kind::TK_SHR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002317 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2318 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2319 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002320 case Token::Kind::TK_BITWISEAND:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002321 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2322 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002323 case Token::Kind::TK_BITWISEOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002324 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2325 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002326 case Token::Kind::TK_BITWISEXOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002327 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2328 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002329 default:
John Stiles5570c512020-11-19 17:58:07 -05002330 fErrors.error(0, "unsupported token");
Ethan Nicholas49465b42019-04-17 12:22:21 -04002331 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002332 }
2333}
2334
Ethan Nicholas49465b42019-04-17 12:22:21 -04002335SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
John Stiles2d4f9592020-10-30 10:29:12 -04002336 const Expression& left = *b.left();
2337 const Expression& right = *b.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002338 Token::Kind op = b.getOperator();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002339 // handle cases where we don't necessarily evaluate both LHS and RHS
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002340 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002341 case Token::Kind::TK_EQ: {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002342 SpvId rhs = this->writeExpression(right, out);
2343 this->getLValue(left, out)->store(rhs, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002344 return rhs;
2345 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002346 case Token::Kind::TK_LOGICALAND:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002347 return this->writeLogicalAnd(b, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002348 case Token::Kind::TK_LOGICALOR:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002349 return this->writeLogicalOr(b, out);
2350 default:
2351 break;
2352 }
2353
2354 std::unique_ptr<LValue> lvalue;
2355 SpvId lhs;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002356 if (Compiler::IsAssignment(op)) {
2357 lvalue = this->getLValue(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002358 lhs = lvalue->load(out);
2359 } else {
2360 lvalue = nullptr;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002361 lhs = this->writeExpression(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002362 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002363 SpvId rhs = this->writeExpression(right, out);
2364 SpvId result = this->writeBinaryExpression(left.type(), lhs, Compiler::RemoveAssignment(op),
2365 right.type(), rhs, b.type(), out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002366 if (lvalue) {
2367 lvalue->store(result, out);
2368 }
2369 return result;
2370}
2371
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002372SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002373 SkASSERT(a.getOperator() == Token::Kind::TK_LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002374 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002375 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
John Stiles2d4f9592020-10-30 10:29:12 -04002376 SpvId lhs = this->writeExpression(*a.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002377 SpvId rhsLabel = this->nextId();
2378 SpvId end = this->nextId();
2379 SpvId lhsBlock = fCurrentBlock;
2380 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2381 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2382 this->writeLabel(rhsLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04002383 SpvId rhs = this->writeExpression(*a.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002384 SpvId rhsBlock = fCurrentBlock;
2385 this->writeInstruction(SpvOpBranch, end, out);
2386 this->writeLabel(end, out);
2387 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002388 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002389 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002390 return result;
2391}
2392
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002393SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002394 SkASSERT(o.getOperator() == Token::Kind::TK_LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002395 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002396 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
John Stiles2d4f9592020-10-30 10:29:12 -04002397 SpvId lhs = this->writeExpression(*o.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002398 SpvId rhsLabel = this->nextId();
2399 SpvId end = this->nextId();
2400 SpvId lhsBlock = fCurrentBlock;
2401 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2402 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2403 this->writeLabel(rhsLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04002404 SpvId rhs = this->writeExpression(*o.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002405 SpvId rhsBlock = fCurrentBlock;
2406 this->writeInstruction(SpvOpBranch, end, out);
2407 this->writeLabel(end, out);
2408 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002409 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002410 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002411 return result;
2412}
2413
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002414SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002415 const Type& type = t.type();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002416 SpvId test = this->writeExpression(*t.test(), out);
2417 if (t.ifTrue()->type().columns() == 1 &&
2418 t.ifTrue()->isCompileTimeConstant() &&
2419 t.ifFalse()->isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002420 // both true and false are constants, can just use OpSelect
2421 SpvId result = this->nextId();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002422 SpvId trueId = this->writeExpression(*t.ifTrue(), out);
2423 SpvId falseId = this->writeExpression(*t.ifFalse(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002424 this->writeInstruction(SpvOpSelect, this->getType(type), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002425 out);
2426 return result;
2427 }
Greg Daniel64773e62016-11-22 09:44:03 -05002428 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002429 // Adreno. Switched to storing the result in a temp variable as glslang does.
2430 SpvId var = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002431 this->writeInstruction(SpvOpVariable, this->getPointerType(type, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002432 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002433 SpvId trueLabel = this->nextId();
2434 SpvId falseLabel = this->nextId();
2435 SpvId end = this->nextId();
2436 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2437 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2438 this->writeLabel(trueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002439 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifTrue(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002440 this->writeInstruction(SpvOpBranch, end, out);
2441 this->writeLabel(falseLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002442 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifFalse(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002443 this->writeInstruction(SpvOpBranch, end, out);
2444 this->writeLabel(end, out);
2445 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002446 this->writeInstruction(SpvOpLoad, this->getType(type), result, var, out);
2447 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002448 return result;
2449}
2450
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002451SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002452 const Type& type = p.type();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002453 if (p.getOperator() == Token::Kind::TK_MINUS) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002454 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002455 SpvId typeId = this->getType(type);
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002456 SpvId expr = this->writeExpression(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002457 if (is_float(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002458 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002459 } else if (is_signed(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002460 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2461 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002462#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002463 ABORT("unsupported prefix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002464#endif
Brian Salomon23356442018-11-30 15:33:19 -05002465 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002466 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002467 return result;
2468 }
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002469 switch (p.getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002470 case Token::Kind::TK_PLUS:
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002471 return this->writeExpression(*p.operand(), out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002472 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002473 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002474 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
2475 SpvId result = this->writeBinaryOperation(type, type, lv->load(out), one,
Greg Daniel64773e62016-11-22 09:44:03 -05002476 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002477 out);
2478 lv->store(result, out);
2479 return result;
2480 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002481 case Token::Kind::TK_MINUSMINUS: {
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, SpvOpFSub,
2485 SpvOpISub, SpvOpISub, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002486 lv->store(result, out);
2487 return result;
2488 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002489 case Token::Kind::TK_LOGICALNOT: {
John Stiles4a7dc462020-11-25 11:08:08 -05002490 SkASSERT(p.operand()->type().isBoolean());
ethannicholasb3058bd2016-07-01 08:22:01 -07002491 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002492 this->writeInstruction(SpvOpLogicalNot, this->getType(type), result,
2493 this->writeExpression(*p.operand(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002494 return result;
2495 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002496 case Token::Kind::TK_BITWISENOT: {
ethannicholas5961bc92016-10-12 06:39:56 -07002497 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002498 this->writeInstruction(SpvOpNot, this->getType(type), result,
2499 this->writeExpression(*p.operand(), out), out);
ethannicholas5961bc92016-10-12 06:39:56 -07002500 return result;
2501 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002502 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002503#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002504 ABORT("unsupported prefix expression: %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002505#endif
2506 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002507 }
2508}
2509
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002510SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002511 const Type& type = p.type();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002512 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002513 SpvId result = lv->load(out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002514 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002515 switch (p.getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002516 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002517 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002518 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2519 lv->store(temp, out);
2520 return result;
2521 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002522 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002523 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002524 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2525 lv->store(temp, out);
2526 return result;
2527 }
2528 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002529#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002530 ABORT("unsupported postfix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002531#endif
2532 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002533 }
2534}
2535
ethannicholasf789b382016-08-03 12:43:36 -07002536SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
Ethan Nicholas59d660c2020-09-28 09:18:15 -04002537 if (b.value()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002538 if (fBoolTrue == 0) {
2539 fBoolTrue = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002540 this->writeInstruction(SpvOpConstantTrue, this->getType(b.type()), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002541 fConstantBuffer);
2542 }
2543 return fBoolTrue;
2544 } else {
2545 if (fBoolFalse == 0) {
2546 fBoolFalse = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002547 this->writeInstruction(SpvOpConstantFalse, this->getType(b.type()), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002548 fConstantBuffer);
2549 }
2550 return fBoolFalse;
2551 }
2552}
2553
ethannicholasf789b382016-08-03 12:43:36 -07002554SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002555 const Type& type = i.type();
2556 ConstantType constantType;
John Stilesfd41d872020-11-25 22:39:45 -05002557 if (type == *fContext.fInt_Type || type.typeKind() == Type::TypeKind::kEnum) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002558 constantType = ConstantType::kInt;
2559 } else if (type == *fContext.fUInt_Type) {
2560 constantType = ConstantType::kUInt;
2561 } else if (type == *fContext.fShort_Type || type == *fContext.fByte_Type) {
2562 constantType = ConstantType::kShort;
2563 } else if (type == *fContext.fUShort_Type || type == *fContext.fUByte_Type) {
2564 constantType = ConstantType::kUShort;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002565 } else {
2566 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002567 }
Ethan Nicholase96cdd12020-09-28 16:27:18 -04002568 std::pair<ConstantValue, ConstantType> key(i.value(), constantType);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002569 auto entry = fNumberConstants.find(key);
2570 if (entry == fNumberConstants.end()) {
2571 SpvId result = this->nextId();
Ethan Nicholase96cdd12020-09-28 16:27:18 -04002572 this->writeInstruction(SpvOpConstant, this->getType(type), result, (SpvId) i.value(),
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002573 fConstantBuffer);
2574 fNumberConstants[key] = result;
2575 return result;
2576 }
2577 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002578}
2579
ethannicholasf789b382016-08-03 12:43:36 -07002580SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002581 const Type& type = f.type();
2582 ConstantType constantType;
2583 if (type == *fContext.fHalf_Type) {
2584 constantType = ConstantType::kHalf;
ethannicholasb3058bd2016-07-01 08:22:01 -07002585 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002586 constantType = ConstantType::kFloat;
ethannicholasb3058bd2016-07-01 08:22:01 -07002587 }
Ethan Nicholasa3f22f12020-10-01 12:13:17 -04002588 float value = (float) f.value();
2589 std::pair<ConstantValue, ConstantType> key(f.value(), constantType);
John Stiles8c578662020-06-01 15:32:47 +00002590 auto entry = fNumberConstants.find(key);
2591 if (entry == fNumberConstants.end()) {
2592 SpvId result = this->nextId();
2593 uint32_t bits;
2594 SkASSERT(sizeof(bits) == sizeof(value));
2595 memcpy(&bits, &value, sizeof(bits));
Ethan Nicholas30d30222020-09-11 12:27:26 -04002596 this->writeInstruction(SpvOpConstant, this->getType(type), result, bits,
John Stiles8c578662020-06-01 15:32:47 +00002597 fConstantBuffer);
2598 fNumberConstants[key] = result;
2599 return result;
2600 }
2601 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002602}
2603
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002604SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002605 SpvId result = fFunctionMap[&f];
Ethan Nicholased84b732020-10-08 11:45:44 -04002606 this->writeInstruction(SpvOpFunction, this->getType(f.returnType()), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002607 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04002608 this->writeInstruction(SpvOpName, result, f.name(), fNameBuffer);
Brian Osman5bf3e202020-10-13 10:34:18 -04002609 const std::vector<const Variable*>& parameters = f.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -04002610 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002611 SpvId id = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -04002612 fVariableMap[parameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002613 SpvId type;
Ethan Nicholased84b732020-10-08 11:45:44 -04002614 type = this->getPointerType(parameters[i]->type(), SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002615 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2616 }
2617 return result;
2618}
2619
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002620SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2621 fVariableBuffer.reset();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002622 SpvId result = this->writeFunctionStart(f.declaration(), out);
Ethan Nicholas7fb39362020-12-16 15:25:19 -05002623 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002624 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002625 StringStream bodyBuffer;
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002626 this->writeBlock((Block&) *f.body(), bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002627 write_stringstream(fVariableBuffer, out);
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002628 if (f.declaration().name() == "main") {
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002629 write_stringstream(fGlobalInitializersBuffer, out);
2630 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002631 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002632 if (fCurrentBlock) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002633 if (f.declaration().returnType() == *fContext.fVoid_Type) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002634 this->writeInstruction(SpvOpReturn, out);
2635 } else {
2636 this->writeInstruction(SpvOpUnreachable, out);
2637 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002638 }
2639 this->writeInstruction(SpvOpFunctionEnd, out);
2640 return result;
2641}
2642
2643void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2644 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002645 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002646 fDecorationBuffer);
2647 }
2648 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002649 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002650 fDecorationBuffer);
2651 }
2652 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002653 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002654 fDecorationBuffer);
2655 }
2656 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002657 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002658 fDecorationBuffer);
2659 }
Greg Daniel64773e62016-11-22 09:44:03 -05002660 if (layout.fInputAttachmentIndex >= 0) {
2661 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2662 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002663 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002664 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002665 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002666 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002667 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002668 fDecorationBuffer);
2669 }
2670}
2671
2672void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2673 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002674 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002675 layout.fLocation, fDecorationBuffer);
2676 }
2677 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002678 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002679 layout.fBinding, fDecorationBuffer);
2680 }
2681 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002682 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002683 layout.fIndex, fDecorationBuffer);
2684 }
2685 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002686 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002687 layout.fSet, fDecorationBuffer);
2688 }
Greg Daniel64773e62016-11-22 09:44:03 -05002689 if (layout.fInputAttachmentIndex >= 0) {
2690 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2691 layout.fInputAttachmentIndex, fDecorationBuffer);
2692 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002693 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002694 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002695 layout.fBuiltin, fDecorationBuffer);
2696 }
2697}
2698
Ethan Nicholas81d15112018-07-13 12:48:50 -04002699static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2700 switch (m.fLayout.fPrimitive) {
2701 case Layout::kPoints_Primitive:
2702 *outSkInCount = 1;
2703 break;
2704 case Layout::kLines_Primitive:
2705 *outSkInCount = 2;
2706 break;
2707 case Layout::kLinesAdjacency_Primitive:
2708 *outSkInCount = 4;
2709 break;
2710 case Layout::kTriangles_Primitive:
2711 *outSkInCount = 3;
2712 break;
2713 case Layout::kTrianglesAdjacency_Primitive:
2714 *outSkInCount = 6;
2715 break;
2716 default:
2717 return;
2718 }
2719}
2720
Stephen White88574972020-06-23 19:09:29 -04002721SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf, bool appendRTHeight) {
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002722 bool isBuffer = ((intf.variable().modifiers().fFlags & Modifiers::kBuffer_Flag) != 0);
2723 bool pushConstant = ((intf.variable().modifiers().fLayout.fFlags &
2724 Layout::kPushConstant_Flag) != 0);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002725 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2726 MemoryLayout(MemoryLayout::k430_Standard) :
2727 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002728 SpvId result = this->nextId();
John Stilesad2d4942020-12-11 16:55:58 -05002729 std::unique_ptr<Type> rtHeightStructType;
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002730 const Type* type = &intf.variable().type();
John Stiles21f5f452020-11-30 09:57:59 -05002731 if (!MemoryLayout::LayoutIsSupported(*type)) {
John Stiles0023c0c2020-11-16 13:32:18 -05002732 fErrors.error(type->fOffset, "type '" + type->name() + "' is not permitted here");
2733 return this->nextId();
2734 }
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002735 Modifiers intfModifiers = intf.variable().modifiers();
2736 SpvStorageClass_ storageClass = get_storage_class(intfModifiers);
Stephen White88574972020-06-23 19:09:29 -04002737 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Greg Daniele6ab9982018-08-22 13:56:32 +00002738 SkASSERT(fRTHeightStructId == (SpvId) -1);
2739 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002740 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002741 fRTHeightStructId = result;
2742 fRTHeightFieldIndex = fields.size();
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002743 fRTHeightStorageClass = storageClass;
John Stilesad2d4942020-12-11 16:55:58 -05002744 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME),
2745 fContext.fFloat_Type.get());
2746 rtHeightStructType = Type::MakeStructType(type->fOffset, type->name(), std::move(fields));
2747 type = rtHeightStructType.get();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002748 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002749 SpvId typeId;
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002750 if (intfModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osman133724c2020-10-28 14:14:39 -04002751 for (const ProgramElement* e : fProgram.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04002752 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04002753 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholas81d15112018-07-13 12:48:50 -04002754 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002755 }
2756 }
John Stilesad2d4942020-12-11 16:55:58 -05002757 typeId = this->getType(
2758 *Type::MakeArrayType("sk_in", intf.variable().type().componentType(), fSkInCount),
2759 memoryLayout);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002760 } else {
2761 typeId = this->getType(*type, memoryLayout);
2762 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002763 if (intfModifiers.fFlags & Modifiers::kBuffer_Flag) {
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002764 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002765 } else if (intfModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002766 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002767 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002768 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002769 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002770 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002771 Layout layout = intfModifiers.fLayout;
2772 if (intfModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002773 layout.fSet = 0;
2774 }
2775 this->writeLayout(layout, result);
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002776 fVariableMap[&intf.variable()] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002777 return result;
2778}
2779
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002780void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002781 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2782}
2783
2784void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2785 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002786 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2787 }
2788}
2789
Brian Osman010ce6a2020-10-19 16:34:10 -04002790bool is_dead(const Variable& var, const ProgramUsage* usage) {
2791 ProgramUsage::VariableCounts counts = usage->get(var);
2792 if (counts.fRead || counts.fWrite) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002793 return false;
2794 }
2795 // not entirely sure what the rules are for when it's safe to elide interface variables, but it
2796 // causes various problems to elide some of them even when dead. But it also causes problems
2797 // *not* to elide sk_SampleMask when it's not being used.
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002798 if (!(var.modifiers().fFlags & (Modifiers::kIn_Flag |
2799 Modifiers::kOut_Flag |
2800 Modifiers::kUniform_Flag |
2801 Modifiers::kBuffer_Flag))) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002802 return true;
2803 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002804 return var.modifiers().fLayout.fBuiltin == SK_SAMPLEMASK_BUILTIN;
Chris Dalton2284aab2019-11-15 11:02:24 -07002805}
2806
ethannicholas5961bc92016-10-12 06:39:56 -07002807#define BUILTIN_IGNORE 9999
Brian Osmanc0213602020-10-06 14:43:32 -04002808void SPIRVCodeGenerator::writeGlobalVar(Program::Kind kind, const VarDeclaration& varDecl,
2809 OutputStream& out) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002810 const Variable& var = varDecl.var();
Brian Osmanc0213602020-10-06 14:43:32 -04002811 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2812 // in the OpenGL backend.
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002813 SkASSERT(!(var.modifiers().fFlags & (Modifiers::kReadOnly_Flag |
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002814 Modifiers::kWriteOnly_Flag |
2815 Modifiers::kCoherent_Flag |
2816 Modifiers::kVolatile_Flag |
2817 Modifiers::kRestrict_Flag)));
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002818 if (var.modifiers().fLayout.fBuiltin == BUILTIN_IGNORE) {
Brian Osmanc0213602020-10-06 14:43:32 -04002819 return;
2820 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002821 if (var.modifiers().fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
Brian Osmanc0213602020-10-06 14:43:32 -04002822 kind != Program::kFragment_Kind) {
2823 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
2824 return;
2825 }
Brian Osman010ce6a2020-10-19 16:34:10 -04002826 if (is_dead(var, fProgram.fUsage.get())) {
Brian Osmanc0213602020-10-06 14:43:32 -04002827 return;
2828 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002829 const Type& type = var.type();
Brian Osmanc0213602020-10-06 14:43:32 -04002830 SpvStorageClass_ storageClass;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002831 if (var.modifiers().fFlags & Modifiers::kIn_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002832 storageClass = SpvStorageClassInput;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002833 } else if (var.modifiers().fFlags & Modifiers::kOut_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002834 storageClass = SpvStorageClassOutput;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002835 } else if (var.modifiers().fFlags & Modifiers::kUniform_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002836 if (type.typeKind() == Type::TypeKind::kSampler ||
2837 type.typeKind() == Type::TypeKind::kSeparateSampler ||
2838 type.typeKind() == Type::TypeKind::kTexture) {
2839 storageClass = SpvStorageClassUniformConstant;
ethannicholasb3058bd2016-07-01 08:22:01 -07002840 } else {
Brian Osmanc0213602020-10-06 14:43:32 -04002841 storageClass = SpvStorageClassUniform;
ethannicholasb3058bd2016-07-01 08:22:01 -07002842 }
Brian Osmanc0213602020-10-06 14:43:32 -04002843 } else {
2844 storageClass = SpvStorageClassPrivate;
2845 }
2846 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002847 fVariableMap[&var] = id;
Brian Osmanc0213602020-10-06 14:43:32 -04002848 SpvId typeId;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002849 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osmanc0213602020-10-06 14:43:32 -04002850 typeId = this->getPointerType(
John Stilesad2d4942020-12-11 16:55:58 -05002851 *Type::MakeArrayType("sk_in", type.componentType(), fSkInCount),
Brian Osmanc0213602020-10-06 14:43:32 -04002852 storageClass);
2853 } else {
2854 typeId = this->getPointerType(type, storageClass);
2855 }
2856 this->writeInstruction(SpvOpVariable, typeId, id, storageClass, fConstantBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002857 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002858 this->writePrecisionModifier(type, id);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002859 if (varDecl.value()) {
Brian Osmanc0213602020-10-06 14:43:32 -04002860 SkASSERT(!fCurrentBlock);
2861 fCurrentBlock = -1;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002862 SpvId value = this->writeExpression(*varDecl.value(), fGlobalInitializersBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002863 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
2864 fCurrentBlock = 0;
2865 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002866 this->writeLayout(var.modifiers().fLayout, id);
2867 if (var.modifiers().fFlags & Modifiers::kFlat_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002868 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2869 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002870 if (var.modifiers().fFlags & Modifiers::kNoPerspective_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002871 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2872 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002873 }
2874}
2875
Brian Osmanc0213602020-10-06 14:43:32 -04002876void SPIRVCodeGenerator::writeVarDeclaration(const VarDeclaration& varDecl, OutputStream& out) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002877 const Variable& var = varDecl.var();
Brian Osmanc0213602020-10-06 14:43:32 -04002878 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2879 // in the OpenGL backend.
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002880 SkASSERT(!(var.modifiers().fFlags & (Modifiers::kReadOnly_Flag |
2881 Modifiers::kWriteOnly_Flag |
2882 Modifiers::kCoherent_Flag |
2883 Modifiers::kVolatile_Flag |
2884 Modifiers::kRestrict_Flag)));
Brian Osmanc0213602020-10-06 14:43:32 -04002885 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002886 fVariableMap[&var] = id;
2887 SpvId type = this->getPointerType(var.type(), SpvStorageClassFunction);
Brian Osmanc0213602020-10-06 14:43:32 -04002888 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002889 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
2890 if (varDecl.value()) {
2891 SpvId value = this->writeExpression(*varDecl.value(), out);
Brian Osmanc0213602020-10-06 14:43:32 -04002892 this->writeInstruction(SpvOpStore, id, value, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002893 }
2894}
2895
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002896void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002897 switch (s.kind()) {
John Stiles98c1f822020-09-09 14:18:53 -04002898 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04002899 case Statement::Kind::kNop:
Ethan Nicholascb670962017-04-20 19:31:52 -04002900 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002901 case Statement::Kind::kBlock:
ethannicholasb3058bd2016-07-01 08:22:01 -07002902 this->writeBlock((Block&) s, out);
2903 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002904 case Statement::Kind::kExpression:
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04002905 this->writeExpression(*s.as<ExpressionStatement>().expression(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002906 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002907 case Statement::Kind::kReturn:
John Stiles26f98502020-08-18 09:30:51 -04002908 this->writeReturnStatement(s.as<ReturnStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002909 break;
Brian Osmanc0213602020-10-06 14:43:32 -04002910 case Statement::Kind::kVarDeclaration:
2911 this->writeVarDeclaration(s.as<VarDeclaration>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002912 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002913 case Statement::Kind::kIf:
John Stiles26f98502020-08-18 09:30:51 -04002914 this->writeIfStatement(s.as<IfStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002915 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002916 case Statement::Kind::kFor:
John Stiles26f98502020-08-18 09:30:51 -04002917 this->writeForStatement(s.as<ForStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002918 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002919 case Statement::Kind::kDo:
John Stiles26f98502020-08-18 09:30:51 -04002920 this->writeDoStatement(s.as<DoStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002921 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002922 case Statement::Kind::kSwitch:
John Stiles26f98502020-08-18 09:30:51 -04002923 this->writeSwitchStatement(s.as<SwitchStatement>(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002924 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002925 case Statement::Kind::kBreak:
ethannicholasb3058bd2016-07-01 08:22:01 -07002926 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2927 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002928 case Statement::Kind::kContinue:
ethannicholasb3058bd2016-07-01 08:22:01 -07002929 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2930 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002931 case Statement::Kind::kDiscard:
ethannicholasb3058bd2016-07-01 08:22:01 -07002932 this->writeInstruction(SpvOpKill, out);
2933 break;
2934 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002935#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002936 ABORT("unsupported statement: %s", s.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002937#endif
2938 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002939 }
2940}
2941
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002942void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04002943 for (const std::unique_ptr<Statement>& stmt : b.children()) {
2944 this->writeStatement(*stmt, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002945 }
2946}
2947
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002948void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002949 SpvId test = this->writeExpression(*stmt.test(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002950 SpvId ifTrue = this->nextId();
2951 SpvId ifFalse = this->nextId();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002952 if (stmt.ifFalse()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002953 SpvId end = this->nextId();
2954 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2955 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2956 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002957 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002958 if (fCurrentBlock) {
2959 this->writeInstruction(SpvOpBranch, end, out);
2960 }
2961 this->writeLabel(ifFalse, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002962 this->writeStatement(*stmt.ifFalse(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002963 if (fCurrentBlock) {
2964 this->writeInstruction(SpvOpBranch, end, out);
2965 }
2966 this->writeLabel(end, out);
2967 } else {
2968 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2969 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2970 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002971 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002972 if (fCurrentBlock) {
2973 this->writeInstruction(SpvOpBranch, ifFalse, out);
2974 }
2975 this->writeLabel(ifFalse, out);
2976 }
2977}
2978
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002979void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04002980 if (f.initializer()) {
2981 this->writeStatement(*f.initializer(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002982 }
2983 SpvId header = this->nextId();
2984 SpvId start = this->nextId();
2985 SpvId body = this->nextId();
2986 SpvId next = this->nextId();
2987 fContinueTarget.push(next);
2988 SpvId end = this->nextId();
2989 fBreakTarget.push(end);
2990 this->writeInstruction(SpvOpBranch, header, out);
2991 this->writeLabel(header, out);
2992 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002993 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002994 this->writeLabel(start, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04002995 if (f.test()) {
2996 SpvId test = this->writeExpression(*f.test(), out);
ethannicholas22f939e2016-10-13 13:25:34 -07002997 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
Ethan Nicholas7fb39362020-12-16 15:25:19 -05002998 } else {
2999 this->writeInstruction(SpvOpBranch, body, out);
ethannicholas22f939e2016-10-13 13:25:34 -07003000 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003001 this->writeLabel(body, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003002 this->writeStatement(*f.statement(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003003 if (fCurrentBlock) {
3004 this->writeInstruction(SpvOpBranch, next, out);
3005 }
3006 this->writeLabel(next, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003007 if (f.next()) {
3008 this->writeExpression(*f.next(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003009 }
3010 this->writeInstruction(SpvOpBranch, header, out);
3011 this->writeLabel(end, out);
3012 fBreakTarget.pop();
3013 fContinueTarget.pop();
3014}
3015
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003016void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003017 SpvId header = this->nextId();
3018 SpvId start = this->nextId();
3019 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003020 SpvId continueTarget = this->nextId();
3021 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003022 SpvId end = this->nextId();
3023 fBreakTarget.push(end);
3024 this->writeInstruction(SpvOpBranch, header, out);
3025 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003026 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003027 this->writeInstruction(SpvOpBranch, start, out);
3028 this->writeLabel(start, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003029 this->writeStatement(*d.statement(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003030 if (fCurrentBlock) {
3031 this->writeInstruction(SpvOpBranch, next, out);
3032 }
3033 this->writeLabel(next, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003034 SpvId test = this->writeExpression(*d.test(), out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003035 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
3036 this->writeLabel(continueTarget, out);
3037 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003038 this->writeLabel(end, out);
3039 fBreakTarget.pop();
3040 fContinueTarget.pop();
3041}
3042
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003043void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04003044 SpvId value = this->writeExpression(*s.value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003045 std::vector<SpvId> labels;
3046 SpvId end = this->nextId();
3047 SpvId defaultLabel = end;
3048 fBreakTarget.push(end);
3049 int size = 3;
John Stiles2d4f9592020-10-30 10:29:12 -04003050 auto& cases = s.cases();
3051 for (const std::unique_ptr<SwitchCase>& c : cases) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003052 SpvId label = this->nextId();
3053 labels.push_back(label);
John Stiles2d4f9592020-10-30 10:29:12 -04003054 if (c->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003055 size += 2;
3056 } else {
3057 defaultLabel = label;
3058 }
3059 }
3060 labels.push_back(end);
3061 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3062 this->writeOpCode(SpvOpSwitch, size, out);
3063 this->writeWord(value, out);
3064 this->writeWord(defaultLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04003065 for (size_t i = 0; i < cases.size(); ++i) {
3066 if (!cases[i]->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003067 continue;
3068 }
John Stiles2d4f9592020-10-30 10:29:12 -04003069 this->writeWord(cases[i]->value()->as<IntLiteral>().value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003070 this->writeWord(labels[i], out);
3071 }
John Stiles2d4f9592020-10-30 10:29:12 -04003072 for (size_t i = 0; i < cases.size(); ++i) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003073 this->writeLabel(labels[i], out);
John Stiles2d4f9592020-10-30 10:29:12 -04003074 for (const auto& stmt : cases[i]->statements()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003075 this->writeStatement(*stmt, out);
3076 }
3077 if (fCurrentBlock) {
3078 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3079 }
3080 }
3081 this->writeLabel(end, out);
3082 fBreakTarget.pop();
3083}
3084
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003085void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003086 if (r.expression()) {
3087 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.expression(), out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003088 out);
3089 } else {
3090 this->writeInstruction(SpvOpReturn, out);
3091 }
3092}
3093
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003094void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003095 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003096 int invocations = 1;
Brian Osman133724c2020-10-28 14:14:39 -04003097 for (const ProgramElement* e : fProgram.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003098 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04003099 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003100 if (m.fFlags & Modifiers::kIn_Flag) {
3101 if (m.fLayout.fInvocations != -1) {
3102 invocations = m.fLayout.fInvocations;
3103 }
3104 SpvId input;
3105 switch (m.fLayout.fPrimitive) {
3106 case Layout::kPoints_Primitive:
3107 input = SpvExecutionModeInputPoints;
3108 break;
3109 case Layout::kLines_Primitive:
3110 input = SpvExecutionModeInputLines;
3111 break;
3112 case Layout::kLinesAdjacency_Primitive:
3113 input = SpvExecutionModeInputLinesAdjacency;
3114 break;
3115 case Layout::kTriangles_Primitive:
3116 input = SpvExecutionModeTriangles;
3117 break;
3118 case Layout::kTrianglesAdjacency_Primitive:
3119 input = SpvExecutionModeInputTrianglesAdjacency;
3120 break;
3121 default:
3122 input = 0;
3123 break;
3124 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003125 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003126 if (input) {
3127 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3128 }
3129 } else if (m.fFlags & Modifiers::kOut_Flag) {
3130 SpvId output;
3131 switch (m.fLayout.fPrimitive) {
3132 case Layout::kPoints_Primitive:
3133 output = SpvExecutionModeOutputPoints;
3134 break;
3135 case Layout::kLineStrip_Primitive:
3136 output = SpvExecutionModeOutputLineStrip;
3137 break;
3138 case Layout::kTriangleStrip_Primitive:
3139 output = SpvExecutionModeOutputTriangleStrip;
3140 break;
3141 default:
3142 output = 0;
3143 break;
3144 }
3145 if (output) {
3146 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3147 }
3148 if (m.fLayout.fMaxVertices != -1) {
3149 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3150 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3151 out);
3152 }
3153 }
3154 }
3155 }
3156 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3157 invocations, out);
3158}
3159
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003160void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003161 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003162 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003163 std::set<SpvId> interfaceVars;
Brian Osman1f8f5752020-10-28 14:46:21 -04003164 // assign IDs to functions
Brian Osman133724c2020-10-28 14:14:39 -04003165 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003166 switch (e->kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04003167 case ProgramElement::Kind::kFunction: {
Brian Osman1179fcf2020-10-08 16:04:40 -04003168 const FunctionDefinition& f = e->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04003169 fFunctionMap[&f.declaration()] = this->nextId();
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003170 break;
3171 }
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003172 default:
3173 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003174 }
3175 }
Brian Osman133724c2020-10-28 14:14:39 -04003176 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003177 if (e->is<InterfaceBlock>()) {
Brian Osman1f8f5752020-10-28 14:46:21 -04003178 const InterfaceBlock& intf = e->as<InterfaceBlock>();
ethannicholasb3058bd2016-07-01 08:22:01 -07003179 SpvId id = this->writeInterfaceBlock(intf);
Brian Osman1f8f5752020-10-28 14:46:21 -04003180
3181 const Modifiers& modifiers = intf.variable().modifiers();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003182 if (((modifiers.fFlags & Modifiers::kIn_Flag) ||
3183 (modifiers.fFlags & Modifiers::kOut_Flag)) &&
3184 modifiers.fLayout.fBuiltin == -1 &&
Brian Osman010ce6a2020-10-19 16:34:10 -04003185 !is_dead(intf.variable(), fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003186 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003187 }
3188 }
3189 }
Brian Osman133724c2020-10-28 14:14:39 -04003190 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003191 if (e->is<GlobalVarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04003192 this->writeGlobalVar(program.fKind,
3193 e->as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>(),
3194 body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003195 }
3196 }
Brian Osman133724c2020-10-28 14:14:39 -04003197 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003198 if (e->is<FunctionDefinition>()) {
3199 this->writeFunction(e->as<FunctionDefinition>(), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003200 }
3201 }
ethannicholasd598f792016-07-25 10:08:54 -07003202 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003203 for (auto entry : fFunctionMap) {
Ethan Nicholase2c49992020-10-05 11:49:11 -04003204 if (entry.first->name() == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003205 main = entry.first;
3206 }
3207 }
Ethan Nicholas1a668d22019-04-18 10:37:40 -04003208 if (!main) {
3209 fErrors.error(0, "program does not contain a main() function");
3210 return;
3211 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003212 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003213 const Variable* var = entry.first;
Ethan Nicholas453f67f2020-10-09 10:43:45 -04003214 if (var->storage() == Variable::Storage::kGlobal &&
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003215 ((var->modifiers().fFlags & Modifiers::kIn_Flag) ||
Brian Osman010ce6a2020-10-19 16:34:10 -04003216 (var->modifiers().fFlags & Modifiers::kOut_Flag)) &&
3217 !is_dead(*var, fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003218 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003219 }
3220 }
3221 this->writeCapabilities(out);
3222 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3223 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003224 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->name().fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003225 (int32_t) interfaceVars.size(), out);
3226 switch (program.fKind) {
3227 case Program::kVertex_Kind:
3228 this->writeWord(SpvExecutionModelVertex, out);
3229 break;
3230 case Program::kFragment_Kind:
3231 this->writeWord(SpvExecutionModelFragment, out);
3232 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003233 case Program::kGeometry_Kind:
3234 this->writeWord(SpvExecutionModelGeometry, out);
3235 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003236 default:
3237 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003238 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003239 SpvId entryPoint = fFunctionMap[main];
3240 this->writeWord(entryPoint, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003241 this->writeString(main->name().fChars, main->name().fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003242 for (int var : interfaceVars) {
3243 this->writeWord(var, out);
3244 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003245 if (program.fKind == Program::kGeometry_Kind) {
3246 this->writeGeometryShaderExecutionMode(entryPoint, out);
3247 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003248 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003249 this->writeInstruction(SpvOpExecutionMode,
3250 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003251 SpvExecutionModeOriginUpperLeft,
3252 out);
3253 }
Brian Osman133724c2020-10-28 14:14:39 -04003254 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003255 if (e->is<Extension>()) {
3256 this->writeInstruction(SpvOpSourceExtension, e->as<Extension>().name().c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003257 }
3258 }
Greg Daniel64773e62016-11-22 09:44:03 -05003259
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003260 write_stringstream(fExtraGlobalsBuffer, out);
3261 write_stringstream(fNameBuffer, out);
3262 write_stringstream(fDecorationBuffer, out);
3263 write_stringstream(fConstantBuffer, out);
3264 write_stringstream(fExternalFunctionsBuffer, out);
3265 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003266}
3267
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003268bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003269 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003270 this->writeWord(SpvMagicNumber, *fOut);
3271 this->writeWord(SpvVersion, *fOut);
3272 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003273 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003274 this->writeInstructions(fProgram, buffer);
3275 this->writeWord(fIdCount, *fOut);
3276 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003277 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003278 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003279}
3280
John Stilesa6841be2020-08-06 14:11:56 -04003281} // namespace SkSL