blob: 08e82cad921cdf25e892aa6848ec4ece785f70db [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
John Stilescd806892021-01-06 13:33:31 -050022#define kLast_Capability SpvCapabilityMultiViewport
23
ethannicholasb3058bd2016-07-01 08:22:01 -070024namespace SkSL {
25
ethannicholasb3058bd2016-07-01 08:22:01 -070026static const int32_t SKSL_MAGIC = 0x0; // FIXME: we should probably register a magic number
27
28void SPIRVCodeGenerator::setupIntrinsics() {
29#define ALL_GLSL(x) std::make_tuple(kGLSL_STD_450_IntrinsicKind, GLSLstd450 ## x, GLSLstd450 ## x, \
30 GLSLstd450 ## x, GLSLstd450 ## x)
31#define BY_TYPE_GLSL(ifFloat, ifInt, ifUInt) std::make_tuple(kGLSL_STD_450_IntrinsicKind, \
32 GLSLstd450 ## ifFloat, \
33 GLSLstd450 ## ifInt, \
34 GLSLstd450 ## ifUInt, \
35 SpvOpUndef)
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040036#define ALL_SPIRV(x) std::make_tuple(kSPIRV_IntrinsicKind, SpvOp ## x, SpvOp ## x, SpvOp ## x, \
37 SpvOp ## x)
ethannicholasb3058bd2016-07-01 08:22:01 -070038#define SPECIAL(x) std::make_tuple(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic, \
39 k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
40 k ## x ## _SpecialIntrinsic)
Ethan Nicholas0df1b042017-03-31 13:56:23 -040041 fIntrinsicMap[String("round")] = ALL_GLSL(Round);
42 fIntrinsicMap[String("roundEven")] = ALL_GLSL(RoundEven);
43 fIntrinsicMap[String("trunc")] = ALL_GLSL(Trunc);
44 fIntrinsicMap[String("abs")] = BY_TYPE_GLSL(FAbs, SAbs, SAbs);
45 fIntrinsicMap[String("sign")] = BY_TYPE_GLSL(FSign, SSign, SSign);
46 fIntrinsicMap[String("floor")] = ALL_GLSL(Floor);
47 fIntrinsicMap[String("ceil")] = ALL_GLSL(Ceil);
48 fIntrinsicMap[String("fract")] = ALL_GLSL(Fract);
49 fIntrinsicMap[String("radians")] = ALL_GLSL(Radians);
50 fIntrinsicMap[String("degrees")] = ALL_GLSL(Degrees);
51 fIntrinsicMap[String("sin")] = ALL_GLSL(Sin);
52 fIntrinsicMap[String("cos")] = ALL_GLSL(Cos);
53 fIntrinsicMap[String("tan")] = ALL_GLSL(Tan);
54 fIntrinsicMap[String("asin")] = ALL_GLSL(Asin);
55 fIntrinsicMap[String("acos")] = ALL_GLSL(Acos);
56 fIntrinsicMap[String("atan")] = SPECIAL(Atan);
57 fIntrinsicMap[String("sinh")] = ALL_GLSL(Sinh);
58 fIntrinsicMap[String("cosh")] = ALL_GLSL(Cosh);
59 fIntrinsicMap[String("tanh")] = ALL_GLSL(Tanh);
60 fIntrinsicMap[String("asinh")] = ALL_GLSL(Asinh);
61 fIntrinsicMap[String("acosh")] = ALL_GLSL(Acosh);
62 fIntrinsicMap[String("atanh")] = ALL_GLSL(Atanh);
63 fIntrinsicMap[String("pow")] = ALL_GLSL(Pow);
64 fIntrinsicMap[String("exp")] = ALL_GLSL(Exp);
65 fIntrinsicMap[String("log")] = ALL_GLSL(Log);
66 fIntrinsicMap[String("exp2")] = ALL_GLSL(Exp2);
67 fIntrinsicMap[String("log2")] = ALL_GLSL(Log2);
68 fIntrinsicMap[String("sqrt")] = ALL_GLSL(Sqrt);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040069 fIntrinsicMap[String("inverse")] = ALL_GLSL(MatrixInverse);
John Stilesa07338f2020-12-17 12:39:08 -050070 fIntrinsicMap[String("outerProduct")] = ALL_SPIRV(OuterProduct);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040071 fIntrinsicMap[String("transpose")] = ALL_SPIRV(Transpose);
John Stiles3679cd12020-12-09 16:22:12 -050072 fIntrinsicMap[String("isinf")] = ALL_SPIRV(IsInf);
73 fIntrinsicMap[String("isnan")] = ALL_SPIRV(IsNan);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040074 fIntrinsicMap[String("inversesqrt")] = ALL_GLSL(InverseSqrt);
75 fIntrinsicMap[String("determinant")] = ALL_GLSL(Determinant);
Brian Osmand1b593f2020-12-28 13:00:46 -050076 fIntrinsicMap[String("matrixCompMult")] = SPECIAL(MatrixCompMult);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040077 fIntrinsicMap[String("matrixInverse")] = ALL_GLSL(MatrixInverse);
Ethan Nicholas70a44b22017-11-30 09:09:16 -050078 fIntrinsicMap[String("mod")] = SPECIAL(Mod);
John Stiles01957272020-12-09 17:14:47 -050079 fIntrinsicMap[String("modf")] = ALL_GLSL(Modf);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050080 fIntrinsicMap[String("min")] = SPECIAL(Min);
81 fIntrinsicMap[String("max")] = SPECIAL(Max);
82 fIntrinsicMap[String("clamp")] = SPECIAL(Clamp);
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040083 fIntrinsicMap[String("saturate")] = SPECIAL(Saturate);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040084 fIntrinsicMap[String("dot")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
Ethan Nicholas0187ae62017-05-03 11:03:44 -040085 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050086 fIntrinsicMap[String("mix")] = SPECIAL(Mix);
Brian Osman6ba3be12020-11-13 16:32:52 -050087 fIntrinsicMap[String("step")] = SPECIAL(Step);
88 fIntrinsicMap[String("smoothstep")] = SPECIAL(SmoothStep);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040089 fIntrinsicMap[String("fma")] = ALL_GLSL(Fma);
90 fIntrinsicMap[String("frexp")] = ALL_GLSL(Frexp);
91 fIntrinsicMap[String("ldexp")] = ALL_GLSL(Ldexp);
ethannicholasb3058bd2016-07-01 08:22:01 -070092
Ethan Nicholas0df1b042017-03-31 13:56:23 -040093#define PACK(type) fIntrinsicMap[String("pack" #type)] = ALL_GLSL(Pack ## type); \
94 fIntrinsicMap[String("unpack" #type)] = ALL_GLSL(Unpack ## type)
ethannicholasb3058bd2016-07-01 08:22:01 -070095 PACK(Snorm4x8);
96 PACK(Unorm4x8);
97 PACK(Snorm2x16);
98 PACK(Unorm2x16);
99 PACK(Half2x16);
100 PACK(Double2x32);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400101 fIntrinsicMap[String("length")] = ALL_GLSL(Length);
102 fIntrinsicMap[String("distance")] = ALL_GLSL(Distance);
103 fIntrinsicMap[String("cross")] = ALL_GLSL(Cross);
104 fIntrinsicMap[String("normalize")] = ALL_GLSL(Normalize);
John Stiles0d19fb42020-12-10 17:04:37 -0500105 fIntrinsicMap[String("faceforward")] = ALL_GLSL(FaceForward);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400106 fIntrinsicMap[String("reflect")] = ALL_GLSL(Reflect);
107 fIntrinsicMap[String("refract")] = ALL_GLSL(Refract);
John Stilese7dc7cb2020-12-22 15:37:14 -0500108 fIntrinsicMap[String("bitCount")] = ALL_SPIRV(BitCount);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400109 fIntrinsicMap[String("findLSB")] = ALL_GLSL(FindILsb);
110 fIntrinsicMap[String("findMSB")] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
111 fIntrinsicMap[String("dFdx")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400112 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700113 fIntrinsicMap[String("dFdy")] = SPECIAL(DFdy);
Chris Dalton09212192018-11-13 15:07:24 -0500114 fIntrinsicMap[String("fwidth")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFwidth,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400115 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400116 fIntrinsicMap[String("makeSampler2D")] = SPECIAL(SampledImage);
117
Ethan Nicholas13863662019-07-29 13:05:15 -0400118 fIntrinsicMap[String("sample")] = SPECIAL(Texture);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400119 fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
Greg Daniel64773e62016-11-22 09:44:03 -0500120
John Stilescc9ff002020-12-09 18:39:41 -0500121 fIntrinsicMap[String("floatBitsToInt")] = ALL_SPIRV(Bitcast);
122 fIntrinsicMap[String("floatBitsToUint")] = ALL_SPIRV(Bitcast);
123 fIntrinsicMap[String("intBitsToFloat")] = ALL_SPIRV(Bitcast);
124 fIntrinsicMap[String("uintBitsToFloat")] = ALL_SPIRV(Bitcast);
125
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400126 fIntrinsicMap[String("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400127 SpvOpUndef, SpvOpUndef, SpvOpAny);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400128 fIntrinsicMap[String("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400129 SpvOpUndef, SpvOpUndef, SpvOpAll);
Brian Osman540c13a2020-11-24 16:55:34 -0500130 fIntrinsicMap[String("not")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
131 SpvOpUndef, SpvOpUndef,
132 SpvOpLogicalNot);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400133 fIntrinsicMap[String("equal")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400134 SpvOpFOrdEqual, SpvOpIEqual,
135 SpvOpIEqual, SpvOpLogicalEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400136 fIntrinsicMap[String("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400137 SpvOpFOrdNotEqual, SpvOpINotEqual,
138 SpvOpINotEqual,
139 SpvOpLogicalNotEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400140 fIntrinsicMap[String("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500141 SpvOpFOrdLessThan, SpvOpSLessThan,
142 SpvOpULessThan, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400143 fIntrinsicMap[String("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500144 SpvOpFOrdLessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400145 SpvOpSLessThanEqual,
146 SpvOpULessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400147 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400148 fIntrinsicMap[String("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500149 SpvOpFOrdGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400150 SpvOpSGreaterThan,
151 SpvOpUGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400152 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400153 fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500154 SpvOpFOrdGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400155 SpvOpSGreaterThanEqual,
156 SpvOpUGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400157 SpvOpUndef);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400158 fIntrinsicMap[String("EmitVertex")] = ALL_SPIRV(EmitVertex);
159 fIntrinsicMap[String("EndPrimitive")] = ALL_SPIRV(EndPrimitive);
ethannicholasb3058bd2016-07-01 08:22:01 -0700160// interpolateAt* not yet supported...
161}
162
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400163void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700164 out.write((const char*) &word, sizeof(word));
ethannicholasb3058bd2016-07-01 08:22:01 -0700165}
166
ethannicholasd598f792016-07-25 10:08:54 -0700167static bool is_float(const Context& context, const Type& type) {
Ethan Nicholas0df21132018-07-10 09:37:51 -0400168 if (type.columns() > 1) {
ethannicholasd598f792016-07-25 10:08:54 -0700169 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700170 }
John Stiles123501f2020-12-09 10:08:13 -0500171 return type.isFloat();
ethannicholasb3058bd2016-07-01 08:22:01 -0700172}
173
ethannicholasd598f792016-07-25 10:08:54 -0700174static bool is_signed(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500175 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700176 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700177 }
John Stiles123501f2020-12-09 10:08:13 -0500178 return type.isSigned();
ethannicholasb3058bd2016-07-01 08:22:01 -0700179}
180
ethannicholasd598f792016-07-25 10:08:54 -0700181static bool is_unsigned(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500182 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700183 return is_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700184 }
John Stiles123501f2020-12-09 10:08:13 -0500185 return type.isUnsigned();
ethannicholasb3058bd2016-07-01 08:22:01 -0700186}
187
ethannicholasd598f792016-07-25 10:08:54 -0700188static bool is_bool(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500189 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700190 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700191 }
John Stiles123501f2020-12-09 10:08:13 -0500192 return type.isBoolean();
ethannicholasb3058bd2016-07-01 08:22:01 -0700193}
194
ethannicholasd598f792016-07-25 10:08:54 -0700195static bool is_out(const Variable& var) {
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400196 return (var.modifiers().fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700197}
198
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400199void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400200 SkASSERT(opCode != SpvOpLoad || &out != &fConstantBuffer);
201 SkASSERT(opCode != SpvOpUndef);
ethannicholasb3058bd2016-07-01 08:22:01 -0700202 switch (opCode) {
203 case SpvOpReturn: // fall through
204 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700205 case SpvOpKill: // fall through
Ethan Nicholas7fb39362020-12-16 15:25:19 -0500206 case SpvOpSwitch: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700207 case SpvOpBranch: // fall through
208 case SpvOpBranchConditional:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400209 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700210 fCurrentBlock = 0;
211 break;
212 case SpvOpConstant: // fall through
213 case SpvOpConstantTrue: // fall through
214 case SpvOpConstantFalse: // fall through
215 case SpvOpConstantComposite: // fall through
216 case SpvOpTypeVoid: // fall through
217 case SpvOpTypeInt: // fall through
218 case SpvOpTypeFloat: // fall through
219 case SpvOpTypeBool: // fall through
220 case SpvOpTypeVector: // fall through
221 case SpvOpTypeMatrix: // fall through
222 case SpvOpTypeArray: // fall through
223 case SpvOpTypePointer: // fall through
224 case SpvOpTypeFunction: // fall through
225 case SpvOpTypeRuntimeArray: // fall through
226 case SpvOpTypeStruct: // fall through
227 case SpvOpTypeImage: // fall through
228 case SpvOpTypeSampledImage: // fall through
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400229 case SpvOpTypeSampler: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700230 case SpvOpVariable: // fall through
231 case SpvOpFunction: // fall through
232 case SpvOpFunctionParameter: // fall through
233 case SpvOpFunctionEnd: // fall through
234 case SpvOpExecutionMode: // fall through
235 case SpvOpMemoryModel: // fall through
236 case SpvOpCapability: // fall through
237 case SpvOpExtInstImport: // fall through
238 case SpvOpEntryPoint: // fall through
239 case SpvOpSource: // fall through
240 case SpvOpSourceExtension: // fall through
241 case SpvOpName: // fall through
242 case SpvOpMemberName: // fall through
243 case SpvOpDecorate: // fall through
244 case SpvOpMemberDecorate:
245 break;
246 default:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400247 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700248 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700249 this->writeWord((length << 16) | opCode, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700250}
251
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400252void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
Ethan Nicholas7fb39362020-12-16 15:25:19 -0500253 SkASSERT(!fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700254 fCurrentBlock = label;
255 this->writeInstruction(SpvOpLabel, label, out);
256}
257
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400258void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700259 this->writeOpCode(opCode, 1, out);
260}
261
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400262void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700263 this->writeOpCode(opCode, 2, out);
264 this->writeWord(word1, out);
265}
266
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700267void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputStream& out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400268 out.write(string, length);
ethannicholasb3058bd2016-07-01 08:22:01 -0700269 switch (length % 4) {
270 case 1:
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 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500274 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400275 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700276 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500277 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700278 break;
279 default:
280 this->writeWord(0, out);
281 }
282}
283
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700284void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out) {
285 this->writeOpCode(opCode, 1 + (string.fLength + 4) / 4, out);
286 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700287}
288
289
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700290void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400291 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700292 this->writeOpCode(opCode, 2 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700293 this->writeWord(word1, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700294 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700295}
296
Greg Daniel64773e62016-11-22 09:44:03 -0500297void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700298 StringFragment string, OutputStream& out) {
299 this->writeOpCode(opCode, 3 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700300 this->writeWord(word1, out);
301 this->writeWord(word2, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700302 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700303}
304
Greg Daniel64773e62016-11-22 09:44:03 -0500305void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400306 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700307 this->writeOpCode(opCode, 3, out);
308 this->writeWord(word1, out);
309 this->writeWord(word2, out);
310}
311
Greg Daniel64773e62016-11-22 09:44:03 -0500312void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400313 int32_t word3, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700314 this->writeOpCode(opCode, 4, out);
315 this->writeWord(word1, out);
316 this->writeWord(word2, out);
317 this->writeWord(word3, out);
318}
319
Greg Daniel64773e62016-11-22 09:44:03 -0500320void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400321 int32_t word3, int32_t word4, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700322 this->writeOpCode(opCode, 5, out);
323 this->writeWord(word1, out);
324 this->writeWord(word2, out);
325 this->writeWord(word3, out);
326 this->writeWord(word4, out);
327}
328
Greg Daniel64773e62016-11-22 09:44:03 -0500329void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
330 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400331 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700332 this->writeOpCode(opCode, 6, out);
333 this->writeWord(word1, out);
334 this->writeWord(word2, out);
335 this->writeWord(word3, out);
336 this->writeWord(word4, out);
337 this->writeWord(word5, out);
338}
339
Greg Daniel64773e62016-11-22 09:44:03 -0500340void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700341 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400342 int32_t word6, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700343 this->writeOpCode(opCode, 7, out);
344 this->writeWord(word1, out);
345 this->writeWord(word2, out);
346 this->writeWord(word3, out);
347 this->writeWord(word4, out);
348 this->writeWord(word5, out);
349 this->writeWord(word6, out);
350}
351
Greg Daniel64773e62016-11-22 09:44:03 -0500352void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700353 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400354 int32_t word6, int32_t word7, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700355 this->writeOpCode(opCode, 8, out);
356 this->writeWord(word1, out);
357 this->writeWord(word2, out);
358 this->writeWord(word3, out);
359 this->writeWord(word4, out);
360 this->writeWord(word5, out);
361 this->writeWord(word6, out);
362 this->writeWord(word7, out);
363}
364
Greg Daniel64773e62016-11-22 09:44:03 -0500365void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700366 int32_t word3, int32_t word4, int32_t word5,
367 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400368 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700369 this->writeOpCode(opCode, 9, out);
370 this->writeWord(word1, out);
371 this->writeWord(word2, out);
372 this->writeWord(word3, out);
373 this->writeWord(word4, out);
374 this->writeWord(word5, out);
375 this->writeWord(word6, out);
376 this->writeWord(word7, out);
377 this->writeWord(word8, out);
378}
379
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400380void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700381 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
382 if (fCapabilities & bit) {
383 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
384 }
385 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400386 if (fProgram.fKind == Program::kGeometry_Kind) {
387 this->writeInstruction(SpvOpCapability, SpvCapabilityGeometry, out);
388 }
Ethan Nicholas81d15112018-07-13 12:48:50 -0400389 else {
390 this->writeInstruction(SpvOpCapability, SpvCapabilityShader, out);
391 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700392}
393
394SpvId SPIRVCodeGenerator::nextId() {
395 return fIdCount++;
396}
397
Ethan Nicholas19671772016-11-28 16:30:17 -0500398void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
399 SpvId resultId) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400400 this->writeInstruction(SpvOpName, resultId, String(type.name()).c_str(), fNameBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700401 // go ahead and write all of the field types, so we don't inadvertently write them while we're
402 // in the middle of writing the struct instruction
403 std::vector<SpvId> types;
404 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500405 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700406 }
407 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
408 this->writeWord(resultId, fConstantBuffer);
409 for (SpvId id : types) {
410 this->writeWord(id, fConstantBuffer);
411 }
412 size_t offset = 0;
413 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400414 const Type::Field& field = type.fields()[i];
John Stiles21f5f452020-11-30 09:57:59 -0500415 if (!MemoryLayout::LayoutIsSupported(*field.fType)) {
John Stiles0023c0c2020-11-16 13:32:18 -0500416 fErrors.error(type.fOffset, "type '" + field.fType->name() + "' is not permitted here");
417 return;
418 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400419 size_t size = memoryLayout.size(*field.fType);
420 size_t alignment = memoryLayout.alignment(*field.fType);
421 const Layout& fieldLayout = field.fModifiers.fLayout;
Ethan Nicholas19671772016-11-28 16:30:17 -0500422 if (fieldLayout.fOffset >= 0) {
Greg Danieldbd44c72017-01-24 15:12:12 -0500423 if (fieldLayout.fOffset < (int) offset) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700424 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400425 "offset of field '" + field.fName + "' must be at "
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500426 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -0500427 }
428 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700429 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400430 "offset of field '" + field.fName + "' must be a multiple"
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500431 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -0500432 }
433 offset = fieldLayout.fOffset;
434 } else {
435 size_t mod = offset % alignment;
436 if (mod) {
437 offset += alignment - mod;
438 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700439 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400440 this->writeInstruction(SpvOpMemberName, resultId, i, field.fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500441 this->writeLayout(fieldLayout, resultId, i);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400442 if (field.fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -0500443 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700444 (SpvId) offset, fDecorationBuffer);
445 }
John Stiles9aeed132020-11-24 17:36:06 -0500446 if (field.fType->isMatrix()) {
Greg Daniel64773e62016-11-22 09:44:03 -0500447 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -0700448 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500449 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400450 (SpvId) memoryLayout.stride(*field.fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800451 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700452 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400453 if (!field.fType->highPrecision()) {
454 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i,
455 SpvDecorationRelaxedPrecision, fDecorationBuffer);
456 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700457 offset += size;
John Stilesc0c51062020-12-03 17:16:29 -0500458 if ((field.fType->isArray() || field.fType->isStruct()) && offset % alignment != 0) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700459 offset += alignment - offset % alignment;
460 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700461 }
462}
463
Ethan Nicholase2c49992020-10-05 11:49:11 -0400464const Type& SPIRVCodeGenerator::getActualType(const Type& type) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500465 if (type.isFloat()) {
John Stiles54e7c052021-01-11 14:22:36 -0500466 return *fContext.fTypes.fFloat;
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400467 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500468 if (type.isSigned()) {
John Stiles54e7c052021-01-11 14:22:36 -0500469 return *fContext.fTypes.fInt;
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400470 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500471 if (type.isUnsigned()) {
John Stiles54e7c052021-01-11 14:22:36 -0500472 return *fContext.fTypes.fUInt;
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400473 }
John Stiles9aeed132020-11-24 17:36:06 -0500474 if (type.isMatrix() || type.isVector()) {
John Stiles54e7c052021-01-11 14:22:36 -0500475 if (type.componentType() == *fContext.fTypes.fHalf) {
476 return fContext.fTypes.fFloat->toCompound(fContext, type.columns(), type.rows());
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400477 }
John Stiles54e7c052021-01-11 14:22:36 -0500478 if (type.componentType() == *fContext.fTypes.fShort ||
479 type.componentType() == *fContext.fTypes.fByte) {
480 return fContext.fTypes.fInt->toCompound(fContext, type.columns(), type.rows());
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400481 }
John Stiles54e7c052021-01-11 14:22:36 -0500482 if (type.componentType() == *fContext.fTypes.fUShort ||
483 type.componentType() == *fContext.fTypes.fUByte) {
484 return fContext.fTypes.fUInt->toCompound(fContext, type.columns(), type.rows());
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400485 }
486 }
487 return type;
488}
489
ethannicholasb3058bd2016-07-01 08:22:01 -0700490SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800491 return this->getType(type, fDefaultLayout);
492}
493
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400494SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400495 const Type& type = this->getActualType(rawType);
Jim Van Verthf3ec9832020-10-21 16:09:57 -0400496 String key = type.name();
John Stilesc0c51062020-12-03 17:16:29 -0500497 if (type.isStruct() || type.isArray()) {
Jim Van Verthf3ec9832020-10-21 16:09:57 -0400498 key += to_string((int)layout.fStd);
499 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800500 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700501 if (entry == fTypeMap.end()) {
502 SpvId result = this->nextId();
Ethan Nicholase6592142020-09-08 10:22:09 -0400503 switch (type.typeKind()) {
504 case Type::TypeKind::kScalar:
John Stiles4a7dc462020-11-25 11:08:08 -0500505 if (type.isBoolean()) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700506 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
John Stiles54e7c052021-01-11 14:22:36 -0500507 } else if (type == *fContext.fTypes.fInt || type == *fContext.fTypes.fShort ||
508 type == *fContext.fTypes.fIntLiteral) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700509 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
John Stiles54e7c052021-01-11 14:22:36 -0500510 } else if (type == *fContext.fTypes.fUInt || type == *fContext.fTypes.fUShort) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700511 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
John Stiles54e7c052021-01-11 14:22:36 -0500512 } else if (type == *fContext.fTypes.fFloat || type == *fContext.fTypes.fHalf ||
513 type == *fContext.fTypes.fFloatLiteral) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700514 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700515 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400516 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700517 }
518 break;
John Stilesfd41d872020-11-25 22:39:45 -0500519 case Type::TypeKind::kEnum:
520 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
521 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400522 case Type::TypeKind::kVector:
Greg Daniel64773e62016-11-22 09:44:03 -0500523 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800524 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700525 type.columns(), fConstantBuffer);
526 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400527 case Type::TypeKind::kMatrix:
Greg Daniel64773e62016-11-22 09:44:03 -0500528 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800529 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700530 type.columns(), fConstantBuffer);
531 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400532 case Type::TypeKind::kStruct:
ethannicholas8ac838d2016-11-22 08:39:36 -0800533 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700534 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400535 case Type::TypeKind::kArray: {
John Stiles21f5f452020-11-30 09:57:59 -0500536 if (!MemoryLayout::LayoutIsSupported(type)) {
537 fErrors.error(type.fOffset, "type '" + type.name() + "' is not permitted here");
538 return this->nextId();
539 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700540 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700541 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500542 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800543 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700544 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500545 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400546 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800547 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700548 } else {
John Stiles5570c512020-11-19 17:58:07 -0500549 // We shouldn't have any runtime-sized arrays right now
550 fErrors.error(type.fOffset, "runtime-sized arrays are not supported in SPIR-V");
Greg Daniel64773e62016-11-22 09:44:03 -0500551 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800552 this->getType(type.componentType(), layout),
553 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400554 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
555 (int32_t) layout.stride(type),
556 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700557 }
558 break;
559 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400560 case Type::TypeKind::kSampler: {
Greg Daniel64773e62016-11-22 09:44:03 -0500561 SpvId image = result;
562 if (SpvDimSubpassData != type.dimensions()) {
Stephen White792e2302019-08-09 13:33:51 -0400563 image = this->getType(type.textureType(), layout);
Greg Daniel64773e62016-11-22 09:44:03 -0500564 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400565 if (SpvDimBuffer == type.dimensions()) {
566 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
567 }
Greg Daniel64773e62016-11-22 09:44:03 -0500568 if (SpvDimSubpassData != type.dimensions()) {
569 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
570 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700571 break;
572 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400573 case Type::TypeKind::kSeparateSampler: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400574 this->writeInstruction(SpvOpTypeSampler, result, fConstantBuffer);
575 break;
576 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400577 case Type::TypeKind::kTexture: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400578 this->writeInstruction(SpvOpTypeImage, result,
John Stiles54e7c052021-01-11 14:22:36 -0500579 this->getType(*fContext.fTypes.fFloat, layout),
John Stilesc0c51062020-12-03 17:16:29 -0500580 type.dimensions(), type.isDepth(), type.isArrayedTexture(),
Stephen White792e2302019-08-09 13:33:51 -0400581 type.isMultisampled(), type.isSampled() ? 1 : 2,
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400582 SpvImageFormatUnknown, fConstantBuffer);
583 fImageTypeMap[key] = result;
584 break;
585 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700586 default:
John Stiles54e7c052021-01-11 14:22:36 -0500587 if (type == *fContext.fTypes.fVoid) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700588 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
589 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500590#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700591 ABORT("invalid type: %s", type.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500592#endif
ethannicholasb3058bd2016-07-01 08:22:01 -0700593 }
594 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800595 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700596 return result;
597 }
598 return entry->second;
599}
600
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400601SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400602 SkASSERT(type.typeKind() == Type::TypeKind::kSampler);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400603 this->getType(type);
604 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400605 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400606 return fImageTypeMap[key];
607}
608
ethannicholasd598f792016-07-25 10:08:54 -0700609SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400610 String key = to_string(this->getType(function.returnType())) + "(";
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400611 String separator;
Brian Osman5bf3e202020-10-13 10:34:18 -0400612 const std::vector<const Variable*>& parameters = function.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400613 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700614 key += separator;
615 separator = ", ";
Ethan Nicholased84b732020-10-08 11:45:44 -0400616 key += to_string(this->getType(parameters[i]->type()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700617 }
618 key += ")";
619 auto entry = fTypeMap.find(key);
620 if (entry == fTypeMap.end()) {
621 SpvId result = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -0400622 int32_t length = 3 + (int32_t) parameters.size();
623 SpvId returnType = this->getType(function.returnType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700624 std::vector<SpvId> parameterTypes;
Ethan Nicholased84b732020-10-08 11:45:44 -0400625 for (size_t i = 0; i < parameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500626 // glslang seems to treat all function arguments as pointers whether they need to be or
627 // not. I was initially puzzled by this until I ran bizarre failures with certain
628 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700629 // failure case:
630 //
631 // void sphere(float x) {
632 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500633 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700634 // void map() {
635 // sphere(1.0);
636 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500637 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700638 // void main() {
639 // for (int i = 0; i < 1; i++) {
640 // map();
641 // }
642 // }
643 //
Greg Daniel64773e62016-11-22 09:44:03 -0500644 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
645 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700646 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
647 // the spec makes this make sense.
648// if (is_out(function->fParameters[i])) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400649 parameterTypes.push_back(this->getPointerType(parameters[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -0700650 SpvStorageClassFunction));
651// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700652// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700653// }
654 }
655 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
656 this->writeWord(result, fConstantBuffer);
657 this->writeWord(returnType, fConstantBuffer);
658 for (SpvId id : parameterTypes) {
659 this->writeWord(id, fConstantBuffer);
660 }
661 fTypeMap[key] = result;
662 return result;
663 }
664 return entry->second;
665}
666
ethannicholas8ac838d2016-11-22 08:39:36 -0800667SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
668 return this->getPointerType(type, fDefaultLayout, storageClass);
669}
670
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400671SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700672 SpvStorageClass_ storageClass) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400673 const Type& type = this->getActualType(rawType);
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500674 String key = type.displayName() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700675 auto entry = fTypeMap.find(key);
676 if (entry == fTypeMap.end()) {
677 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500678 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700679 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700680 fTypeMap[key] = result;
681 return result;
682 }
683 return entry->second;
684}
685
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400686SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400687 switch (expr.kind()) {
688 case Expression::Kind::kBinary:
John Stiles81365af2020-08-18 09:24:00 -0400689 return this->writeBinaryExpression(expr.as<BinaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400690 case Expression::Kind::kBoolLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400691 return this->writeBoolLiteral(expr.as<BoolLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400692 case Expression::Kind::kConstructor:
John Stiles81365af2020-08-18 09:24:00 -0400693 return this->writeConstructor(expr.as<Constructor>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400694 case Expression::Kind::kIntLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400695 return this->writeIntLiteral(expr.as<IntLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400696 case Expression::Kind::kFieldAccess:
John Stiles81365af2020-08-18 09:24:00 -0400697 return this->writeFieldAccess(expr.as<FieldAccess>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400698 case Expression::Kind::kFloatLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400699 return this->writeFloatLiteral(expr.as<FloatLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400700 case Expression::Kind::kFunctionCall:
John Stiles81365af2020-08-18 09:24:00 -0400701 return this->writeFunctionCall(expr.as<FunctionCall>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400702 case Expression::Kind::kPrefix:
John Stiles81365af2020-08-18 09:24:00 -0400703 return this->writePrefixExpression(expr.as<PrefixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400704 case Expression::Kind::kPostfix:
John Stiles81365af2020-08-18 09:24:00 -0400705 return this->writePostfixExpression(expr.as<PostfixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400706 case Expression::Kind::kSwizzle:
John Stiles81365af2020-08-18 09:24:00 -0400707 return this->writeSwizzle(expr.as<Swizzle>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400708 case Expression::Kind::kVariableReference:
John Stiles81365af2020-08-18 09:24:00 -0400709 return this->writeVariableReference(expr.as<VariableReference>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400710 case Expression::Kind::kTernary:
John Stiles81365af2020-08-18 09:24:00 -0400711 return this->writeTernaryExpression(expr.as<TernaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400712 case Expression::Kind::kIndex:
John Stiles81365af2020-08-18 09:24:00 -0400713 return this->writeIndexExpression(expr.as<IndexExpression>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700714 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500715#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700716 ABORT("unsupported expression: %s", expr.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500717#endif
718 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700719 }
720 return -1;
721}
722
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400723SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400724 const FunctionDeclaration& function = c.function();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400725 auto intrinsic = fIntrinsicMap.find(function.name());
John Stiles93e661a2020-12-08 16:17:00 -0500726 if (intrinsic == fIntrinsicMap.end()) {
727 fErrors.error(c.fOffset, "unsupported intrinsic '" + function.description() + "'");
728 return -1;
729 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700730 int32_t intrinsicId;
John Stiles89ac7c22020-12-30 17:47:31 -0500731 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400732 if (arguments.size() > 0) {
733 const Type& type = arguments[0]->type();
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400734 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
735 intrinsicId = std::get<1>(intrinsic->second);
736 } else if (is_signed(fContext, type)) {
737 intrinsicId = std::get<2>(intrinsic->second);
738 } else if (is_unsigned(fContext, type)) {
739 intrinsicId = std::get<3>(intrinsic->second);
740 } else if (is_bool(fContext, type)) {
741 intrinsicId = std::get<4>(intrinsic->second);
742 } else {
743 intrinsicId = std::get<1>(intrinsic->second);
744 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700745 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400746 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700747 }
748 switch (std::get<0>(intrinsic->second)) {
749 case kGLSL_STD_450_IntrinsicKind: {
750 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400751 std::vector<SpvId> argumentIds;
752 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400753 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400754 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400755 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400756 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400757 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700758 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400759 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400760 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700761 this->writeWord(result, out);
762 this->writeWord(fGLSLExtendedInstructions, out);
763 this->writeWord(intrinsicId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400764 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700765 this->writeWord(id, out);
766 }
767 return result;
768 }
769 case kSPIRV_IntrinsicKind: {
Brian Osman46787d52020-11-24 14:18:23 -0500770 // GLSL supports dot(float, float), but SPIR-V does not. Convert it to FMul
John Stiles9aeed132020-11-24 17:36:06 -0500771 if (intrinsicId == SpvOpDot && arguments[0]->type().isScalar()) {
Brian Osman46787d52020-11-24 14:18:23 -0500772 intrinsicId = SpvOpFMul;
773 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700774 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400775 std::vector<SpvId> argumentIds;
776 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400777 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400778 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400779 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400780 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400781 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700782 }
John Stiles54e7c052021-01-11 14:22:36 -0500783 if (c.type() != *fContext.fTypes.fVoid) {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400784 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400785 this->writeWord(this->getType(c.type()), out);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400786 this->writeWord(result, out);
787 } else {
788 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
789 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400790 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700791 this->writeWord(id, out);
792 }
793 return result;
794 }
795 case kSpecial_IntrinsicKind:
796 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
797 default:
John Stiles93e661a2020-12-08 16:17:00 -0500798 fErrors.error(c.fOffset, "unsupported intrinsic '" + function.description() + "'");
799 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700800 }
801}
802
John Stiles8e3b6be2020-10-13 11:14:08 -0400803std::vector<SpvId> SPIRVCodeGenerator::vectorize(const ExpressionArray& args, OutputStream& out) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500804 int vectorSize = 0;
805 for (const auto& a : args) {
John Stiles9aeed132020-11-24 17:36:06 -0500806 if (a->type().isVector()) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500807 if (vectorSize) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400808 SkASSERT(a->type().columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500809 }
810 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400811 vectorSize = a->type().columns();
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500812 }
813 }
814 }
815 std::vector<SpvId> result;
John Stiles8e3b6be2020-10-13 11:14:08 -0400816 result.reserve(args.size());
Ethan Nicholas30d30222020-09-11 12:27:26 -0400817 for (const auto& arg : args) {
818 const Type& argType = arg->type();
819 SpvId raw = this->writeExpression(*arg, out);
John Stiles9aeed132020-11-24 17:36:06 -0500820 if (vectorSize && argType.isScalar()) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500821 SpvId vector = this->nextId();
822 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400823 this->writeWord(this->getType(argType.toCompound(fContext, vectorSize, 1)), out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500824 this->writeWord(vector, out);
825 for (int i = 0; i < vectorSize; i++) {
826 this->writeWord(raw, out);
827 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400828 this->writePrecisionModifier(argType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500829 result.push_back(vector);
830 } else {
831 result.push_back(raw);
832 }
833 }
834 return result;
835}
836
837void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
838 SpvId signedInst, SpvId unsignedInst,
839 const std::vector<SpvId>& args,
840 OutputStream& out) {
841 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
842 this->writeWord(this->getType(type), out);
843 this->writeWord(id, out);
844 this->writeWord(fGLSLExtendedInstructions, out);
845
846 if (is_float(fContext, type)) {
847 this->writeWord(floatInst, out);
848 } else if (is_signed(fContext, type)) {
849 this->writeWord(signedInst, out);
850 } else if (is_unsigned(fContext, type)) {
851 this->writeWord(unsignedInst, out);
852 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400853 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500854 }
855 for (SpvId a : args) {
856 this->writeWord(a, out);
857 }
858}
859
Greg Daniel64773e62016-11-22 09:44:03 -0500860SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400861 OutputStream& out) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400862 const ExpressionArray& arguments = c.arguments();
ethannicholasb3058bd2016-07-01 08:22:01 -0700863 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400864 const Type& callType = c.type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700865 switch (kind) {
866 case kAtan_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400867 std::vector<SpvId> argumentIds;
868 for (const std::unique_ptr<Expression>& arg : arguments) {
869 argumentIds.push_back(this->writeExpression(*arg, out));
ethannicholasb3058bd2016-07-01 08:22:01 -0700870 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400871 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400872 this->writeWord(this->getType(callType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700873 this->writeWord(result, out);
874 this->writeWord(fGLSLExtendedInstructions, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400875 this->writeWord(argumentIds.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
876 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700877 this->writeWord(id, out);
878 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400879 break;
880 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400881 case kSampledImage_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400882 SkASSERT(arguments.size() == 2);
883 SpvId img = this->writeExpression(*arguments[0], out);
884 SpvId sampler = this->writeExpression(*arguments[1], out);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400885 this->writeInstruction(SpvOpSampledImage,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400886 this->getType(callType),
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400887 result,
888 img,
889 sampler,
890 out);
891 break;
892 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400893 case kSubpassLoad_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400894 SpvId img = this->writeExpression(*arguments[0], out);
John Stiles8e3b6be2020-10-13 11:14:08 -0400895 ExpressionArray args;
John Stilesf4bda742020-10-14 16:57:41 -0400896 args.reserve_back(2);
John Stiles8e3b6be2020-10-13 11:14:08 -0400897 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
898 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
John Stiles54e7c052021-01-11 14:22:36 -0500899 Constructor ctor(-1, fContext.fTypes.fInt2.get(), std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400900 SpvId coords = this->writeConstantVector(ctor);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400901 if (arguments.size() == 1) {
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400902 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400903 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400904 result,
905 img,
906 coords,
907 out);
908 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400909 SkASSERT(arguments.size() == 2);
910 SpvId sample = this->writeExpression(*arguments[1], out);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400911 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400912 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400913 result,
914 img,
915 coords,
916 SpvImageOperandsSampleMask,
917 sample,
918 out);
919 }
920 break;
921 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700922 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500923 SpvOp_ op = SpvOpImageSampleImplicitLod;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400924 const Type& arg1Type = arguments[1]->type();
925 switch (arguments[0]->type().dimensions()) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500926 case SpvDim1D:
John Stiles54e7c052021-01-11 14:22:36 -0500927 if (arg1Type == *fContext.fTypes.fFloat2) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500928 op = SpvOpImageSampleProjImplicitLod;
929 } else {
John Stiles54e7c052021-01-11 14:22:36 -0500930 SkASSERT(arg1Type == *fContext.fTypes.fFloat);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500931 }
932 break;
933 case SpvDim2D:
John Stiles54e7c052021-01-11 14:22:36 -0500934 if (arg1Type == *fContext.fTypes.fFloat3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500935 op = SpvOpImageSampleProjImplicitLod;
936 } else {
John Stiles54e7c052021-01-11 14:22:36 -0500937 SkASSERT(arg1Type == *fContext.fTypes.fFloat2);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500938 }
939 break;
940 case SpvDim3D:
John Stiles54e7c052021-01-11 14:22:36 -0500941 if (arg1Type == *fContext.fTypes.fFloat4) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500942 op = SpvOpImageSampleProjImplicitLod;
943 } else {
John Stiles54e7c052021-01-11 14:22:36 -0500944 SkASSERT(arg1Type == *fContext.fTypes.fFloat3);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500945 }
946 break;
947 case SpvDimCube: // fall through
948 case SpvDimRect: // fall through
949 case SpvDimBuffer: // fall through
950 case SpvDimSubpassData:
951 break;
952 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400953 SpvId type = this->getType(callType);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400954 SpvId sampler = this->writeExpression(*arguments[0], out);
955 SpvId uv = this->writeExpression(*arguments[1], out);
956 if (arguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500957 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700958 SpvImageOperandsBiasMask,
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400959 this->writeExpression(*arguments[2], out),
ethannicholasb3058bd2016-07-01 08:22:01 -0700960 out);
961 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400962 SkASSERT(arguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500963 if (fProgram.fSettings.fSharpenTextures) {
964 FloatLiteral lodBias(fContext, -1, -0.5);
965 this->writeInstruction(op, type, result, sampler, uv,
966 SpvImageOperandsBiasMask,
967 this->writeFloatLiteral(lodBias),
968 out);
969 } else {
970 this->writeInstruction(op, type, result, sampler, uv,
971 out);
972 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700973 }
974 break;
975 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500976 case kMod_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400977 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400978 SkASSERT(args.size() == 2);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400979 const Type& operandType = arguments[0]->type();
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500980 SpvOp_ op;
981 if (is_float(fContext, operandType)) {
982 op = SpvOpFMod;
983 } else if (is_signed(fContext, operandType)) {
984 op = SpvOpSMod;
985 } else if (is_unsigned(fContext, operandType)) {
986 op = SpvOpUMod;
987 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400988 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500989 return 0;
990 }
991 this->writeOpCode(op, 5, out);
992 this->writeWord(this->getType(operandType), out);
993 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500994 this->writeWord(args[0], out);
995 this->writeWord(args[1], out);
996 break;
997 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700998 case kDFdy_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400999 SpvId fn = this->writeExpression(*arguments[0], out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -07001000 this->writeOpCode(SpvOpDPdy, 4, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001001 this->writeWord(this->getType(callType), out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -07001002 this->writeWord(result, out);
1003 this->writeWord(fn, out);
1004 if (fProgram.fSettings.fFlipY) {
1005 // Flipping Y also negates the Y derivatives.
1006 SpvId flipped = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001007 this->writeInstruction(SpvOpFNegate, this->getType(callType), flipped, result,
1008 out);
1009 this->writePrecisionModifier(callType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -07001010 return flipped;
1011 }
1012 break;
1013 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001014 case kClamp_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001015 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001016 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001017 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001018 GLSLstd450UClamp, args, out);
1019 break;
1020 }
1021 case kMax_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001022 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001023 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001024 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMax, GLSLstd450SMax,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001025 GLSLstd450UMax, args, out);
1026 break;
1027 }
1028 case kMin_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001029 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001030 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001031 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMin, GLSLstd450SMin,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001032 GLSLstd450UMin, args, out);
1033 break;
1034 }
1035 case kMix_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001036 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001037 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001038 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMix, SpvOpUndef,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001039 SpvOpUndef, args, out);
1040 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -05001041 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001042 case kSaturate_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001043 SkASSERT(arguments.size() == 1);
John Stiles8e3b6be2020-10-13 11:14:08 -04001044 ExpressionArray finalArgs;
John Stilesf4bda742020-10-14 16:57:41 -04001045 finalArgs.reserve_back(3);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001046 finalArgs.push_back(arguments[0]->clone());
John Stiles8e3b6be2020-10-13 11:14:08 -04001047 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1048 /*value=*/0));
1049 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1050 /*value=*/1));
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001051 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001052 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001053 GLSLstd450UClamp, spvArgs, out);
1054 break;
1055 }
Brian Osman6ba3be12020-11-13 16:32:52 -05001056 case kSmoothStep_SpecialIntrinsic: {
1057 std::vector<SpvId> args = this->vectorize(arguments, out);
1058 SkASSERT(args.size() == 3);
1059 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450SmoothStep, SpvOpUndef,
1060 SpvOpUndef, args, out);
1061 break;
1062 }
1063 case kStep_SpecialIntrinsic: {
1064 std::vector<SpvId> args = this->vectorize(arguments, out);
1065 SkASSERT(args.size() == 2);
1066 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450Step, SpvOpUndef,
1067 SpvOpUndef, args, out);
1068 break;
1069 }
Brian Osmand1b593f2020-12-28 13:00:46 -05001070 case kMatrixCompMult_SpecialIntrinsic: {
1071 SkASSERT(arguments.size() == 2);
1072 SpvId lhs = this->writeExpression(*arguments[0], out);
1073 SpvId rhs = this->writeExpression(*arguments[1], out);
1074 result = this->writeComponentwiseMatrixBinary(callType, lhs, rhs, SpvOpFMul, SpvOpUndef,
1075 out);
1076 break;
1077 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001078 }
1079 return result;
1080}
1081
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001082SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001083 const FunctionDeclaration& function = c.function();
John Stiles89ac7c22020-12-30 17:47:31 -05001084 if (function.isBuiltin() && !function.definition()) {
1085 return this->writeIntrinsicCall(c, out);
1086 }
John Stiles8e3b6be2020-10-13 11:14:08 -04001087 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001088 const auto& entry = fFunctionMap.find(&function);
ethannicholasb3058bd2016-07-01 08:22:01 -07001089 if (entry == fFunctionMap.end()) {
John Stiles89ac7c22020-12-30 17:47:31 -05001090 fErrors.error(c.fOffset, "function '" + function.description() + "' is not defined");
1091 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001092 }
1093 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001094 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001095 std::vector<SpvId> argumentIds;
1096 for (size_t i = 0; i < arguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001097 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001098 // passed directly
1099 SpvId tmpVar;
1100 // if we need a temporary var to store this argument, this is the value to store in the var
1101 SpvId tmpValueId;
Ethan Nicholased84b732020-10-08 11:45:44 -04001102 if (is_out(*function.parameters()[i])) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001103 std::unique_ptr<LValue> lv = this->getLValue(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001104 SpvId ptr = lv->getPointer();
1105 if (ptr) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001106 argumentIds.push_back(ptr);
ethannicholasb3058bd2016-07-01 08:22:01 -07001107 continue;
1108 } else {
1109 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1110 // copy it into a temp, call the function, read the value out of the temp, and then
1111 // update the lvalue.
1112 tmpValueId = lv->load(out);
1113 tmpVar = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001114 lvalues.push_back(std::make_tuple(tmpVar, &arguments[i]->type(), std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001115 }
1116 } else {
1117 // see getFunctionType for an explanation of why we're always using pointer parameters
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001118 tmpValueId = this->writeExpression(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001119 tmpVar = this->nextId();
1120 }
Greg Daniel64773e62016-11-22 09:44:03 -05001121 this->writeInstruction(SpvOpVariable,
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001122 this->getPointerType(arguments[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001123 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001124 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001125 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001126 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001127 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001128 argumentIds.push_back(tmpVar);
ethannicholasb3058bd2016-07-01 08:22:01 -07001129 }
1130 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001131 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001132 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001133 this->writeWord(result, out);
1134 this->writeWord(entry->second, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001135 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001136 this->writeWord(id, out);
1137 }
1138 // now that the call is complete, we may need to update some lvalues with the new values of out
1139 // arguments
1140 for (const auto& tuple : lvalues) {
1141 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001142 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1143 out);
1144 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001145 std::get<2>(tuple)->store(load, out);
1146 }
1147 return result;
1148}
1149
ethannicholasf789b382016-08-03 12:43:36 -07001150SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001151 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001152 SkASSERT(type.isVector() && c.isCompileTimeConstant());
John Stilescd806892021-01-06 13:33:31 -05001153
John Stiles9cfaa4f2021-01-06 17:52:00 -05001154 // Get each of the constructor components as SPIR-V constants.
John Stilescd806892021-01-06 13:33:31 -05001155 SPIRVVectorConstant key{this->getType(type),
1156 /*fValueId=*/{SpvId(-1), SpvId(-1), SpvId(-1), SpvId(-1)}};
John Stiles9cfaa4f2021-01-06 17:52:00 -05001157
1158 if (c.componentType().isFloat()) {
1159 for (int i = 0; i < type.columns(); i++) {
1160 FloatLiteral literal(c.fOffset, c.getFVecComponent(i), &c.componentType());
1161 key.fValueId[i] = this->writeFloatLiteral(literal);
1162 }
1163 } else if (c.componentType().isInteger()) {
1164 for (int i = 0; i < type.columns(); i++) {
1165 IntLiteral literal(c.fOffset, c.getIVecComponent(i), &c.componentType());
1166 key.fValueId[i] = this->writeIntLiteral(literal);
1167 }
1168 } else if (c.componentType().isBoolean()) {
1169 for (int i = 0; i < type.columns(); i++) {
1170 BoolLiteral literal(c.fOffset, c.getBVecComponent(i), &c.componentType());
1171 key.fValueId[i] = this->writeBoolLiteral(literal);
ethannicholasb3058bd2016-07-01 08:22:01 -07001172 }
1173 } else {
John Stiles9cfaa4f2021-01-06 17:52:00 -05001174 SkDEBUGFAILF("unexpected vector component type: %s",
1175 c.componentType().displayName().c_str());
1176 return SpvId(-1);
ethannicholasb3058bd2016-07-01 08:22:01 -07001177 }
John Stilescd806892021-01-06 13:33:31 -05001178
1179 // Check to see if we've already synthesized this vector constant.
1180 auto [iter, newlyCreated] = fVectorConstants.insert({key, (SpvId)-1});
1181 if (newlyCreated) {
1182 // Emit an OpConstantComposite instruction for this constant.
1183 SpvId result = this->nextId();
John Stiles9cfaa4f2021-01-06 17:52:00 -05001184 this->writeOpCode(SpvOpConstantComposite, 3 + type.columns(), fConstantBuffer);
John Stilescd806892021-01-06 13:33:31 -05001185 this->writeWord(key.fTypeId, fConstantBuffer);
1186 this->writeWord(result, fConstantBuffer);
John Stiles9cfaa4f2021-01-06 17:52:00 -05001187 for (int i = 0; i < type.columns(); i++) {
John Stilescd806892021-01-06 13:33:31 -05001188 this->writeWord(key.fValueId[i], fConstantBuffer);
1189 }
1190 iter->second = result;
1191 }
1192 return iter->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07001193}
1194
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001195SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001196 SkASSERT(c.arguments().size() == 1);
John Stilesd9d52712021-01-13 17:15:02 -05001197 SkASSERT(c.type().isFloat());
1198 const Expression& ctorExpr = *c.arguments()[0];
1199 SpvId expressionId = this->writeExpression(ctorExpr, out);
1200 return this->castScalarToFloat(expressionId, ctorExpr.type(), c.type(), out);
1201}
1202
1203SpvId SPIRVCodeGenerator::castScalarToFloat(SpvId inputId, const Type& inputType,
1204 const Type& outputType, OutputStream& out) {
1205 // Casting a float to float is a no-op.
1206 if (inputType.isFloat()) {
1207 return inputId;
1208 }
1209
1210 // Given the input type, generate the appropriate instruction to cast to float.
ethannicholasb3058bd2016-07-01 08:22:01 -07001211 SpvId result = this->nextId();
John Stilesd9d52712021-01-13 17:15:02 -05001212 if (inputType.isBoolean()) {
John Stilesba4b0e92021-01-05 13:55:39 -05001213 // Use OpSelect to convert the boolean argument to a literal 1.0 or 0.0.
1214 FloatLiteral one(fContext, /*offset=*/-1, /*value=*/1);
1215 SpvId oneID = this->writeFloatLiteral(one);
1216 FloatLiteral zero(fContext, /*offset=*/-1, /*value=*/0);
1217 SpvId zeroID = this->writeFloatLiteral(zero);
John Stilesd9d52712021-01-13 17:15:02 -05001218 this->writeInstruction(SpvOpSelect, this->getType(outputType), result,
1219 inputId, oneID, zeroID, out);
1220 } else if (inputType.isSigned()) {
1221 this->writeInstruction(SpvOpConvertSToF, this->getType(outputType), result, inputId, out);
1222 } else if (inputType.isUnsigned()) {
1223 this->writeInstruction(SpvOpConvertUToF, this->getType(outputType), result, inputId, out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001224 } else {
John Stilesd9d52712021-01-13 17:15:02 -05001225 SkDEBUGFAILF("unsupported type for float typecast: %s", inputType.description().c_str());
1226 return (SpvId)-1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001227 }
1228 return result;
1229}
1230
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001231SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001232 SkASSERT(c.arguments().size() == 1);
John Stilesd9d52712021-01-13 17:15:02 -05001233 SkASSERT(c.type().isSigned());
1234 const Expression& ctorExpr = *c.arguments()[0];
1235 SpvId expressionId = this->writeExpression(ctorExpr, out);
1236 return this->castScalarToSignedInt(expressionId, ctorExpr.type(), c.type(), out);
1237}
1238
1239SpvId SPIRVCodeGenerator::castScalarToSignedInt(SpvId inputId, const Type& inputType,
1240 const Type& outputType, OutputStream& out) {
1241 // Casting a signed int to signed int is a no-op.
1242 if (inputType.isSigned()) {
1243 return inputId;
1244 }
1245
1246 // Given the input type, generate the appropriate instruction to cast to signed int.
ethannicholasb3058bd2016-07-01 08:22:01 -07001247 SpvId result = this->nextId();
John Stilesd9d52712021-01-13 17:15:02 -05001248 if (inputType.isBoolean()) {
John Stilesba4b0e92021-01-05 13:55:39 -05001249 // Use OpSelect to convert the boolean argument to a literal 1 or 0.
John Stiles54e7c052021-01-11 14:22:36 -05001250 IntLiteral one(/*offset=*/-1, /*value=*/1, fContext.fTypes.fInt.get());
John Stilesba4b0e92021-01-05 13:55:39 -05001251 SpvId oneID = this->writeIntLiteral(one);
John Stiles54e7c052021-01-11 14:22:36 -05001252 IntLiteral zero(/*offset=*/-1, /*value=*/0, fContext.fTypes.fInt.get());
John Stilesba4b0e92021-01-05 13:55:39 -05001253 SpvId zeroID = this->writeIntLiteral(zero);
John Stilesd9d52712021-01-13 17:15:02 -05001254 this->writeInstruction(SpvOpSelect, this->getType(outputType), result,
1255 inputId, oneID, zeroID, out);
1256 } else if (inputType.isFloat()) {
1257 this->writeInstruction(SpvOpConvertFToS, this->getType(outputType), result, inputId, out);
1258 } else if (inputType.isUnsigned()) {
1259 this->writeInstruction(SpvOpBitcast, this->getType(outputType), result, inputId, out);
1260 } else {
1261 SkDEBUGFAILF("unsupported type for signed int typecast: %s",
1262 inputType.description().c_str());
1263 return (SpvId)-1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001264 }
1265 return result;
1266}
1267
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001268SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001269 SkASSERT(c.arguments().size() == 1);
John Stilesd9d52712021-01-13 17:15:02 -05001270 SkASSERT(c.type().isUnsigned());
1271 const Expression& ctorExpr = *c.arguments()[0];
1272 SpvId expressionId = this->writeExpression(ctorExpr, out);
1273 return this->castScalarToUnsignedInt(expressionId, ctorExpr.type(), c.type(), out);
1274}
1275
1276SpvId SPIRVCodeGenerator::castScalarToUnsignedInt(SpvId inputId, const Type& inputType,
1277 const Type& outputType, OutputStream& out) {
1278 // Casting an unsigned int to unsigned int is a no-op.
1279 if (inputType.isUnsigned()) {
1280 return inputId;
1281 }
1282
1283 // Given the input type, generate the appropriate instruction to cast to signed int.
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001284 SpvId result = this->nextId();
John Stilesd9d52712021-01-13 17:15:02 -05001285 if (inputType.isBoolean()) {
John Stilesba4b0e92021-01-05 13:55:39 -05001286 // Use OpSelect to convert the boolean argument to a literal 1u or 0u.
John Stiles54e7c052021-01-11 14:22:36 -05001287 IntLiteral one(/*offset=*/-1, /*value=*/1, fContext.fTypes.fUInt.get());
John Stilesba4b0e92021-01-05 13:55:39 -05001288 SpvId oneID = this->writeIntLiteral(one);
John Stiles54e7c052021-01-11 14:22:36 -05001289 IntLiteral zero(/*offset=*/-1, /*value=*/0, fContext.fTypes.fUInt.get());
John Stilesba4b0e92021-01-05 13:55:39 -05001290 SpvId zeroID = this->writeIntLiteral(zero);
John Stilesd9d52712021-01-13 17:15:02 -05001291 this->writeInstruction(SpvOpSelect, this->getType(outputType), result,
1292 inputId, oneID, zeroID, out);
1293 } else if (inputType.isFloat()) {
1294 this->writeInstruction(SpvOpConvertFToU, this->getType(outputType), result, inputId, out);
1295 } else if (inputType.isSigned()) {
1296 this->writeInstruction(SpvOpBitcast, this->getType(outputType), result, inputId, out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001297 } else {
John Stilesd9d52712021-01-13 17:15:02 -05001298 SkDEBUGFAILF("unsupported type for unsigned int typecast: %s",
1299 inputType.description().c_str());
1300 return (SpvId)-1;
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001301 }
1302 return result;
1303}
1304
Ethan Nicholas84645e32017-02-09 13:57:14 -05001305void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001306 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001307 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001308 SpvId zeroId = this->writeFloatLiteral(zero);
1309 std::vector<SpvId> columnIds;
1310 for (int column = 0; column < type.columns(); column++) {
1311 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1312 out);
1313 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1314 out);
1315 SpvId columnId = this->nextId();
1316 this->writeWord(columnId, out);
1317 columnIds.push_back(columnId);
1318 for (int row = 0; row < type.columns(); row++) {
1319 this->writeWord(row == column ? diagonal : zeroId, out);
1320 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001321 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001322 }
1323 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1324 out);
1325 this->writeWord(this->getType(type), out);
1326 this->writeWord(id, out);
John Stilesf621e232020-08-25 13:33:02 -04001327 for (SpvId columnId : columnIds) {
1328 this->writeWord(columnId, out);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001329 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001330 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001331}
1332
1333void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001334 const Type& dstType, OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05001335 SkASSERT(srcType.isMatrix());
1336 SkASSERT(dstType.isMatrix());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001337 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001338 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1339 srcType.rows(),
1340 1));
1341 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1342 dstType.rows(),
1343 1));
1344 SpvId zeroId;
John Stiles54e7c052021-01-11 14:22:36 -05001345 if (dstType.componentType() == *fContext.fTypes.fFloat) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001346 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001347 zeroId = this->writeFloatLiteral(zero);
John Stiles54e7c052021-01-11 14:22:36 -05001348 } else if (dstType.componentType() == *fContext.fTypes.fInt) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001349 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001350 zeroId = this->writeIntLiteral(zero);
1351 } else {
1352 ABORT("unsupported matrix component type");
1353 }
1354 SpvId zeroColumn = 0;
1355 SpvId columns[4];
1356 for (int i = 0; i < dstType.columns(); i++) {
1357 if (i < srcType.columns()) {
1358 // we're still inside the src matrix, copy the column
1359 SpvId srcColumn = this->nextId();
1360 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001361 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001362 SpvId dstColumn;
1363 if (srcType.rows() == dstType.rows()) {
1364 // columns are equal size, don't need to do anything
1365 dstColumn = srcColumn;
1366 }
1367 else if (dstType.rows() > srcType.rows()) {
1368 // dst column is bigger, need to zero-pad it
1369 dstColumn = this->nextId();
1370 int delta = dstType.rows() - srcType.rows();
1371 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1372 this->writeWord(dstColumnType, out);
1373 this->writeWord(dstColumn, out);
1374 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001375 for (int j = 0; j < delta; ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001376 this->writeWord(zeroId, out);
1377 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001378 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001379 }
1380 else {
1381 // dst column is smaller, need to swizzle the src column
1382 dstColumn = this->nextId();
1383 int count = dstType.rows();
1384 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1385 this->writeWord(dstColumnType, out);
1386 this->writeWord(dstColumn, out);
1387 this->writeWord(srcColumn, out);
1388 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001389 for (int j = 0; j < count; j++) {
1390 this->writeWord(j, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001391 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001392 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001393 }
1394 columns[i] = dstColumn;
1395 } else {
1396 // we're past the end of the src matrix, need a vector of zeroes
1397 if (!zeroColumn) {
1398 zeroColumn = this->nextId();
1399 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1400 this->writeWord(dstColumnType, out);
1401 this->writeWord(zeroColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001402 for (int j = 0; j < dstType.rows(); ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001403 this->writeWord(zeroId, out);
1404 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001405 this->writePrecisionModifier(dstType, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001406 }
1407 columns[i] = zeroColumn;
1408 }
1409 }
1410 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1411 this->writeWord(this->getType(dstType), out);
1412 this->writeWord(id, out);
1413 for (int i = 0; i < dstType.columns(); i++) {
1414 this->writeWord(columns[i], out);
1415 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001416 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001417}
1418
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001419void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1420 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001421 std::vector<SpvId>* columnIds,
1422 int* currentCount, int rows, SpvId entry,
1423 OutputStream& out) {
1424 SkASSERT(*currentCount < rows);
1425 ++(*currentCount);
1426 currentColumn->push_back(entry);
1427 if (*currentCount == rows) {
1428 *currentCount = 0;
1429 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1430 this->writeWord(columnType, out);
1431 SpvId columnId = this->nextId();
1432 this->writeWord(columnId, out);
1433 columnIds->push_back(columnId);
1434 for (SpvId id : *currentColumn) {
1435 this->writeWord(id, out);
1436 }
1437 currentColumn->clear();
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001438 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001439 }
1440}
1441
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001442SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001443 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001444 SkASSERT(type.isMatrix());
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001445 SkASSERT(c.arguments().size() > 0);
1446 const Type& arg0Type = c.arguments()[0]->type();
ethannicholasb3058bd2016-07-01 08:22:01 -07001447 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1448 // an instruction
1449 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001450 for (size_t i = 0; i < c.arguments().size(); i++) {
1451 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001452 }
1453 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001454 int rows = type.rows();
1455 int columns = type.columns();
John Stiles9aeed132020-11-24 17:36:06 -05001456 if (arguments.size() == 1 && arg0Type.isScalar()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001457 this->writeUniformScaleMatrix(result, arguments[0], type, out);
John Stiles9aeed132020-11-24 17:36:06 -05001458 } else if (arguments.size() == 1 && arg0Type.isMatrix()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001459 this->writeMatrixCopy(result, arguments[0], arg0Type, type, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001460 } else if (arguments.size() == 1 &&
John Stiles9aeed132020-11-24 17:36:06 -05001461 arg0Type.isVector()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001462 SkASSERT(type.rows() == 2 && type.columns() == 2);
1463 SkASSERT(arg0Type.columns() == 4);
1464 SpvId componentType = this->getType(type.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001465 SpvId v[4];
1466 for (int i = 0; i < 4; ++i) {
1467 v[i] = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001468 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i,
1469 out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001470 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001471 SpvId columnType = this->getType(type.componentType().toCompound(fContext, 2, 1));
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001472 SpvId column1 = this->nextId();
1473 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1474 SpvId column2 = this->nextId();
1475 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001476 this->writeInstruction(SpvOpCompositeConstruct, this->getType(type), result, column1,
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001477 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001478 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001479 SpvId columnType = this->getType(type.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001480 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001481 // ids of vectors and scalars we have written to the current column so far
1482 std::vector<SpvId> currentColumn;
1483 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001484 int currentCount = 0;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001485 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001486 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001487 const Type& argType = c.arguments()[i]->type();
John Stiles9aeed132020-11-24 17:36:06 -05001488 if (currentCount == 0 && argType.isVector() &&
Ethan Nicholas30d30222020-09-11 12:27:26 -04001489 argType.columns() == type.rows()) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001490 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001491 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001492 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001493 if (argType.columns() == 1) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001494 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1495 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001496 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001497 SpvId componentType = this->getType(argType.componentType());
1498 for (int j = 0; j < argType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001499 SpvId swizzle = this->nextId();
1500 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1501 arguments[i], j, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001502 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1503 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001504 }
1505 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001506 }
1507 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001508 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001509 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001510 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001511 this->writeWord(result, out);
1512 for (SpvId id : columnIds) {
1513 this->writeWord(id, out);
1514 }
1515 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001516 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001517 return result;
1518}
1519
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001520SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001521 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001522 SkASSERT(type.isVector());
Brian Osman0247e9e2020-12-23 15:07:11 -05001523 // Constructing a vector from another vector (even if it's constant) requires our general
1524 // case code, to deal with (possible) per-element type conversion.
1525 bool vectorToVector = c.arguments().size() == 1 && c.arguments()[0]->type().isVector();
1526 if (c.isCompileTimeConstant() && !vectorToVector) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001527 return this->writeConstantVector(c);
1528 }
1529 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1530 // an instruction
1531 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001532 for (size_t i = 0; i < c.arguments().size(); i++) {
1533 const Type& argType = c.arguments()[i]->type();
John Stiles9aeed132020-11-24 17:36:06 -05001534 if (argType.isVector()) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001535 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1536 // extract the components and convert them in that case manually. On top of that,
John Stilesd5e59b62021-01-13 13:09:26 -05001537 // as of this writing there's a bug in the Intel Vulkan driver where
1538 // OpCompositeConstruct doesn't handle vector arguments at all, so we always extract
1539 // vector components and pass them into OpCompositeConstruct individually.
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001540 SpvId vec = this->writeExpression(*c.arguments()[i], out);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001541 SpvOp_ op = SpvOpUndef;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001542 const Type& src = argType.componentType();
1543 const Type& dst = type.componentType();
John Stiles54e7c052021-01-11 14:22:36 -05001544 if (dst == *fContext.fTypes.fFloat || dst == *fContext.fTypes.fHalf) {
1545 if (src == *fContext.fTypes.fFloat || src == *fContext.fTypes.fHalf) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001546 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001547 return vec;
1548 }
John Stiles54e7c052021-01-11 14:22:36 -05001549 } else if (src == *fContext.fTypes.fInt ||
1550 src == *fContext.fTypes.fShort ||
1551 src == *fContext.fTypes.fByte) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001552 op = SpvOpConvertSToF;
John Stiles54e7c052021-01-11 14:22:36 -05001553 } else if (src == *fContext.fTypes.fUInt ||
1554 src == *fContext.fTypes.fUShort ||
1555 src == *fContext.fTypes.fUByte) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001556 op = SpvOpConvertUToF;
1557 } else {
John Stilesd5e59b62021-01-13 13:09:26 -05001558 fErrors.error(c.arguments()[i]->fOffset, "unsupported cast in SPIR-V: vector " +
1559 src.description() + " to " +
1560 dst.description());
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001561 }
John Stiles54e7c052021-01-11 14:22:36 -05001562 } else if (dst == *fContext.fTypes.fInt ||
1563 dst == *fContext.fTypes.fShort ||
1564 dst == *fContext.fTypes.fByte) {
1565 if (src == *fContext.fTypes.fFloat || src == *fContext.fTypes.fHalf) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001566 op = SpvOpConvertFToS;
John Stiles54e7c052021-01-11 14:22:36 -05001567 } else if (src == *fContext.fTypes.fInt ||
1568 src == *fContext.fTypes.fShort ||
1569 src == *fContext.fTypes.fByte) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001570 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001571 return vec;
1572 }
John Stiles54e7c052021-01-11 14:22:36 -05001573 } else if (src == *fContext.fTypes.fUInt ||
1574 src == *fContext.fTypes.fUShort ||
1575 src == *fContext.fTypes.fUByte) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001576 op = SpvOpBitcast;
1577 } else {
John Stilesd5e59b62021-01-13 13:09:26 -05001578 fErrors.error(c.arguments()[i]->fOffset, "unsupported cast in SPIR-V: vector " +
1579 src.description() + " to " +
1580 dst.description());
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001581 }
John Stiles54e7c052021-01-11 14:22:36 -05001582 } else if (dst == *fContext.fTypes.fUInt ||
1583 dst == *fContext.fTypes.fUShort ||
1584 dst == *fContext.fTypes.fUByte) {
1585 if (src == *fContext.fTypes.fFloat || src == *fContext.fTypes.fHalf) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001586 op = SpvOpConvertFToS;
John Stiles54e7c052021-01-11 14:22:36 -05001587 } else if (src == *fContext.fTypes.fInt ||
1588 src == *fContext.fTypes.fShort ||
1589 src == *fContext.fTypes.fByte) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001590 op = SpvOpBitcast;
John Stiles54e7c052021-01-11 14:22:36 -05001591 } else if (src == *fContext.fTypes.fUInt ||
1592 src == *fContext.fTypes.fUShort ||
1593 src == *fContext.fTypes.fUByte) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001594 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001595 return vec;
1596 }
1597 } else {
John Stilesd5e59b62021-01-13 13:09:26 -05001598 fErrors.error(c.arguments()[i]->fOffset, "unsupported cast in SPIR-V: vector " +
1599 src.description() + " to " +
1600 dst.description());
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001601 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001602 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001603 for (int j = 0; j < argType.columns(); j++) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001604 SpvId swizzle = this->nextId();
1605 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1606 out);
1607 if (op != SpvOpUndef) {
1608 SpvId cast = this->nextId();
1609 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1610 arguments.push_back(cast);
1611 } else {
1612 arguments.push_back(swizzle);
1613 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001614 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001615 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001616 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001617 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001618 }
1619 SpvId result = this->nextId();
John Stiles9aeed132020-11-24 17:36:06 -05001620 if (arguments.size() == 1 && c.arguments()[0]->type().isScalar()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001621 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(), out);
1622 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001623 this->writeWord(result, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001624 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001625 this->writeWord(arguments[0], out);
1626 }
1627 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001628 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001629 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001630 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001631 this->writeWord(result, out);
1632 for (SpvId id : arguments) {
1633 this->writeWord(id, out);
1634 }
1635 }
1636 return result;
1637}
1638
Ethan Nicholasbd553222017-07-18 15:54:59 -04001639SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001640 const Type& type = c.type();
John Stilesc0c51062020-12-03 17:16:29 -05001641 SkASSERT(type.isArray());
Ethan Nicholasbd553222017-07-18 15:54:59 -04001642 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1643 // an instruction
1644 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001645 for (size_t i = 0; i < c.arguments().size(); i++) {
1646 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholasbd553222017-07-18 15:54:59 -04001647 }
1648 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001649 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.arguments().size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001650 this->writeWord(this->getType(type), out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001651 this->writeWord(result, out);
1652 for (SpvId id : arguments) {
1653 this->writeWord(id, out);
1654 }
1655 return result;
1656}
1657
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001658SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001659 const Type& type = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001660 if (c.arguments().size() == 1 &&
1661 this->getActualType(type) == this->getActualType(c.arguments()[0]->type())) {
1662 return this->writeExpression(*c.arguments()[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001663 }
John Stilese3183552021-01-13 19:34:17 -05001664 if (type.isFloat()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001665 return this->writeFloatConstructor(c, out);
John Stilese3183552021-01-13 19:34:17 -05001666 } else if (type.isSigned()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001667 return this->writeIntConstructor(c, out);
John Stilese3183552021-01-13 19:34:17 -05001668 } else if (type.isUnsigned()) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001669 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001670 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001671 switch (type.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001672 case Type::TypeKind::kVector:
ethannicholasb3058bd2016-07-01 08:22:01 -07001673 return this->writeVectorConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001674 case Type::TypeKind::kMatrix:
ethannicholasb3058bd2016-07-01 08:22:01 -07001675 return this->writeMatrixConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001676 case Type::TypeKind::kArray:
Ethan Nicholasbd553222017-07-18 15:54:59 -04001677 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001678 default:
John Stilese3183552021-01-13 19:34:17 -05001679 fErrors.error(c.fOffset, "unsupported constructor: " + c.description());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001680 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001681 }
1682}
1683
1684SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1685 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001686 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001687 return SpvStorageClassInput;
1688 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001689 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001690 return SpvStorageClassOutput;
1691 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001692 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001693 return SpvStorageClassPushConstant;
1694 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001695 return SpvStorageClassUniform;
1696 } else {
1697 return SpvStorageClassFunction;
1698 }
1699}
1700
ethannicholasf789b382016-08-03 12:43:36 -07001701SpvStorageClass_ get_storage_class(const Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001702 switch (expr.kind()) {
1703 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -04001704 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001705 if (var.storage() != Variable::Storage::kGlobal) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001706 return SpvStorageClassFunction;
1707 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001708 SpvStorageClass_ result = get_storage_class(var.modifiers());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001709 if (result == SpvStorageClassFunction) {
1710 result = SpvStorageClassPrivate;
1711 }
1712 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001713 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001714 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001715 return get_storage_class(*expr.as<FieldAccess>().base());
Ethan Nicholase6592142020-09-08 10:22:09 -04001716 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001717 return get_storage_class(*expr.as<IndexExpression>().base());
ethannicholasb3058bd2016-07-01 08:22:01 -07001718 default:
1719 return SpvStorageClassFunction;
1720 }
1721}
1722
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001723std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001724 std::vector<SpvId> chain;
Ethan Nicholase6592142020-09-08 10:22:09 -04001725 switch (expr.kind()) {
1726 case Expression::Kind::kIndex: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001727 IndexExpression& indexExpr = (IndexExpression&) expr;
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001728 chain = this->getAccessChain(*indexExpr.base(), out);
1729 chain.push_back(this->writeExpression(*indexExpr.index(), out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001730 break;
1731 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001732 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001733 FieldAccess& fieldExpr = (FieldAccess&) expr;
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001734 chain = this->getAccessChain(*fieldExpr.base(), out);
1735 IntLiteral index(fContext, -1, fieldExpr.fieldIndex());
ethannicholasb3058bd2016-07-01 08:22:01 -07001736 chain.push_back(this->writeIntLiteral(index));
1737 break;
1738 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001739 default: {
1740 SpvId id = this->getLValue(expr, out)->getPointer();
1741 SkASSERT(id != 0);
1742 chain.push_back(id);
1743 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001744 }
1745 return chain;
1746}
1747
1748class PointerLValue : public SPIRVCodeGenerator::LValue {
1749public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001750 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1751 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001752 : fGen(gen)
1753 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001754 , fType(type)
1755 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001756
John Stiles1cf2c8d2020-08-13 22:58:04 -04001757 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001758 return fPointer;
1759 }
1760
John Stiles1cf2c8d2020-08-13 22:58:04 -04001761 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001762 SpvId result = fGen.nextId();
1763 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001764 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001765 return result;
1766 }
1767
John Stiles1cf2c8d2020-08-13 22:58:04 -04001768 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001769 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1770 }
1771
1772private:
1773 SPIRVCodeGenerator& fGen;
1774 const SpvId fPointer;
1775 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001776 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001777};
1778
1779class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1780public:
John Stiles750109b2020-10-30 13:45:46 -04001781 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const ComponentArray& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001782 const Type& baseType, const Type& swizzleType,
1783 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001784 : fGen(gen)
1785 , fVecPointer(vecPointer)
1786 , fComponents(components)
1787 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001788 , fSwizzleType(swizzleType)
1789 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001790
John Stiles1cf2c8d2020-08-13 22:58:04 -04001791 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001792 return 0;
1793 }
1794
John Stiles1cf2c8d2020-08-13 22:58:04 -04001795 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001796 SpvId base = fGen.nextId();
1797 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001798 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001799 SpvId result = fGen.nextId();
1800 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1801 fGen.writeWord(fGen.getType(fSwizzleType), out);
1802 fGen.writeWord(result, out);
1803 fGen.writeWord(base, out);
1804 fGen.writeWord(base, out);
1805 for (int component : fComponents) {
1806 fGen.writeWord(component, out);
1807 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001808 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001809 return result;
1810 }
1811
John Stiles1cf2c8d2020-08-13 22:58:04 -04001812 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001813 // use OpVectorShuffle to mix and match the vector components. We effectively create
1814 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001815 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001816 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001817 // float3L = ...;
1818 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001819 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001820 // 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 -07001821 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1822 // (3, 1, 4).
1823 SpvId base = fGen.nextId();
1824 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1825 SpvId shuffle = fGen.nextId();
1826 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1827 fGen.writeWord(fGen.getType(fBaseType), out);
1828 fGen.writeWord(shuffle, out);
1829 fGen.writeWord(base, out);
1830 fGen.writeWord(value, out);
1831 for (int i = 0; i < fBaseType.columns(); i++) {
1832 // current offset into the virtual vector, defaults to pulling the unmodified
1833 // value from the left side
1834 int offset = i;
1835 // check to see if we are writing this component
1836 for (size_t j = 0; j < fComponents.size(); j++) {
1837 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001838 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001839 // the correct component of the right side instead of preserving the
1840 // value from the left
1841 offset = (int) (j + fBaseType.columns());
1842 break;
1843 }
1844 }
1845 fGen.writeWord(offset, out);
1846 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001847 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001848 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1849 }
1850
1851private:
1852 SPIRVCodeGenerator& fGen;
1853 const SpvId fVecPointer;
John Stiles750109b2020-10-30 13:45:46 -04001854 const ComponentArray& fComponents;
ethannicholasb3058bd2016-07-01 08:22:01 -07001855 const Type& fBaseType;
1856 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001857 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001858};
1859
Greg Daniel64773e62016-11-22 09:44:03 -05001860std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001861 OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001862 const Type& type = expr.type();
1863 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
Ethan Nicholase6592142020-09-08 10:22:09 -04001864 switch (expr.kind()) {
1865 case Expression::Kind::kVariableReference: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001866 SpvId typeId;
Ethan Nicholas78686922020-10-08 06:46:27 -04001867 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001868 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
John Stilesad2d4942020-12-11 16:55:58 -05001869 typeId = this->getType(*Type::MakeArrayType("sk_in", var.type().componentType(),
1870 fSkInCount));
Ethan Nicholas5226b772018-05-03 16:20:41 -04001871 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001872 typeId = this->getType(type);
Ethan Nicholas5226b772018-05-03 16:20:41 -04001873 }
ethannicholasd598f792016-07-25 10:08:54 -07001874 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001875 SkASSERT(entry != fVariableMap.end());
John Stiles5570c512020-11-19 17:58:07 -05001876 return std::make_unique<PointerLValue>(*this, entry->second, typeId, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001877 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001878 case Expression::Kind::kIndex: // fall through
1879 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001880 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1881 SpvId member = this->nextId();
1882 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001883 this->writeWord(this->getPointerType(type, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001884 this->writeWord(member, out);
1885 for (SpvId idx : chain) {
1886 this->writeWord(idx, out);
1887 }
John Stiles5570c512020-11-19 17:58:07 -05001888 return std::make_unique<PointerLValue>(*this, member, this->getType(type), precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001889 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001890 case Expression::Kind::kSwizzle: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001891 Swizzle& swizzle = (Swizzle&) expr;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001892 size_t count = swizzle.components().size();
1893 SpvId base = this->getLValue(*swizzle.base(), out)->getPointer();
John Stiles5570c512020-11-19 17:58:07 -05001894 if (!base) {
1895 fErrors.error(swizzle.fOffset, "unable to retrieve lvalue from swizzle");
1896 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001897 if (count == 1) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001898 IntLiteral index(fContext, -1, swizzle.components()[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001899 SpvId member = this->nextId();
1900 this->writeInstruction(SpvOpAccessChain,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001901 this->getPointerType(type,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001902 get_storage_class(*swizzle.base())),
Greg Daniel64773e62016-11-22 09:44:03 -05001903 member,
1904 base,
1905 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001906 out);
John Stiles5570c512020-11-19 17:58:07 -05001907 return std::make_unique<PointerLValue>(*this, member, this->getType(type),
1908 precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001909 } else {
John Stiles5570c512020-11-19 17:58:07 -05001910 return std::make_unique<SwizzleLValue>(*this, base, swizzle.components(),
1911 swizzle.base()->type(), type, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001912 }
1913 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001914 case Expression::Kind::kTernary: {
Ethan Nicholasa583b812018-01-18 13:32:11 -05001915 TernaryExpression& t = (TernaryExpression&) expr;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001916 SpvId test = this->writeExpression(*t.test(), out);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001917 SpvId end = this->nextId();
1918 SpvId ifTrueLabel = this->nextId();
1919 SpvId ifFalseLabel = this->nextId();
1920 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1921 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1922 this->writeLabel(ifTrueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04001923 SpvId ifTrue = this->getLValue(*t.ifTrue(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001924 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001925 this->writeInstruction(SpvOpBranch, end, out);
1926 ifTrueLabel = fCurrentBlock;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001927 SpvId ifFalse = this->getLValue(*t.ifFalse(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001928 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001929 ifFalseLabel = fCurrentBlock;
1930 this->writeInstruction(SpvOpBranch, end, out);
1931 SpvId result = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05001932 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fTypes.fBool), result, ifTrue,
Ethan Nicholasa583b812018-01-18 13:32:11 -05001933 ifTrueLabel, ifFalse, ifFalseLabel, out);
John Stiles5570c512020-11-19 17:58:07 -05001934 return std::make_unique<PointerLValue>(*this, result, this->getType(type), precision);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001935 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001936 default: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001937 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001938 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001939 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1940 // caught by IRGenerator
1941 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001942 SpvId pointerType = this->getPointerType(type, SpvStorageClassFunction);
1943 this->writeInstruction(SpvOpVariable, pointerType, result, SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001944 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001945 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
John Stiles5570c512020-11-19 17:58:07 -05001946 return std::make_unique<PointerLValue>(*this, result, this->getType(type), precision);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001947 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001948 }
1949}
1950
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001951SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001952 SpvId result = this->nextId();
Ethan Nicholas78686922020-10-08 06:46:27 -04001953 auto entry = fVariableMap.find(ref.variable());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001954 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001955 SpvId var = entry->second;
Ethan Nicholas78686922020-10-08 06:46:27 -04001956 this->writeInstruction(SpvOpLoad, this->getType(ref.variable()->type()), result, var, out);
1957 this->writePrecisionModifier(ref.variable()->type(), result);
1958 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
Brian Osmane38bedd2020-12-21 11:51:54 -05001959 fProgram.fSettings.fFlipY) {
Greg Daniela85e4bf2020-06-17 16:32:45 -04001960 // The x component never changes, so just grab it
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001961 SpvId xId = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05001962 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fTypes.fFloat), xId,
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001963 result, 0, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001964
1965 // Calculate the y component which may need to be flipped
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001966 SpvId rawYId = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05001967 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fTypes.fFloat),
1968 rawYId, result, 1, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001969 SpvId flippedYId = 0;
1970 if (fProgram.fSettings.fFlipY) {
1971 // need to remap to a top-left coordinate system
1972 if (fRTHeightStructId == (SpvId)-1) {
1973 // height variable hasn't been written yet
Greg Daniela85e4bf2020-06-17 16:32:45 -04001974 SkASSERT(fRTHeightFieldIndex == (SpvId)-1);
1975 std::vector<Type::Field> fields;
John Stiles5570c512020-11-19 17:58:07 -05001976 if (fProgram.fSettings.fRTHeightOffset < 0) {
1977 fErrors.error(ref.fOffset, "RTHeightOffset is negative");
1978 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001979 fields.emplace_back(
1980 Modifiers(Layout(0, -1, fProgram.fSettings.fRTHeightOffset, -1, -1, -1, -1,
1981 -1, Layout::Format::kUnspecified,
1982 Layout::kUnspecified_Primitive, 1, -1, "", "",
1983 Layout::kNo_Key, Layout::CType::kDefault),
1984 0),
John Stiles54e7c052021-01-11 14:22:36 -05001985 SKSL_RTHEIGHT_NAME, fContext.fTypes.fFloat.get());
Greg Daniela85e4bf2020-06-17 16:32:45 -04001986 StringFragment name("sksl_synthetic_uniforms");
John Stilesad2d4942020-12-11 16:55:58 -05001987 std::unique_ptr<Type> intfStruct = Type::MakeStructType(/*offset=*/-1, name,
1988 fields);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001989 int binding = fProgram.fSettings.fRTHeightBinding;
John Stiles5570c512020-11-19 17:58:07 -05001990 if (binding == -1) {
1991 fErrors.error(ref.fOffset, "layout(binding=...) is required in SPIR-V");
1992 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001993 int set = fProgram.fSettings.fRTHeightSet;
John Stiles5570c512020-11-19 17:58:07 -05001994 if (set == -1) {
1995 fErrors.error(ref.fOffset, "layout(set=...) is required in SPIR-V");
1996 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001997 Layout layout(0, -1, -1, binding, -1, set, -1, -1, Layout::Format::kUnspecified,
1998 Layout::kUnspecified_Primitive, -1, -1, "", "", Layout::kNo_Key,
1999 Layout::CType::kDefault);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002000 Modifiers modifiers(layout, Modifiers::kUniform_Flag);
John Stiles3ae071e2020-08-05 15:29:29 -04002001 const Variable* intfVar = fSynthetics.takeOwnershipOfSymbol(
2002 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -05002003 fProgram.fModifiers->addToPool(modifiers),
John Stiles3ae071e2020-08-05 15:29:29 -04002004 name,
John Stilesad2d4942020-12-11 16:55:58 -05002005 intfStruct.get(),
Brian Osman3887a012020-09-30 13:22:27 -04002006 /*builtin=*/false,
Ethan Nicholas453f67f2020-10-09 10:43:45 -04002007 Variable::Storage::kGlobal));
John Stilesd39aec02020-12-03 10:42:26 -05002008 InterfaceBlock intf(/*offset=*/-1, intfVar, name,
2009 /*instanceName=*/"", /*arraySize=*/0,
John Stiles7c3515b2020-10-16 18:38:39 -04002010 std::make_shared<SymbolTable>(&fErrors, /*builtin=*/false));
Stephen White88574972020-06-23 19:09:29 -04002011
2012 fRTHeightStructId = this->writeInterfaceBlock(intf, false);
Greg Daniela85e4bf2020-06-17 16:32:45 -04002013 fRTHeightFieldIndex = 0;
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002014 fRTHeightStorageClass = SpvStorageClassUniform;
Greg Daniela85e4bf2020-06-17 16:32:45 -04002015 }
2016 SkASSERT(fRTHeightFieldIndex != (SpvId)-1);
2017
2018 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
2019 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
2020 SpvId heightPtr = this->nextId();
2021 this->writeOpCode(SpvOpAccessChain, 5, out);
John Stiles54e7c052021-01-11 14:22:36 -05002022 this->writeWord(this->getPointerType(*fContext.fTypes.fFloat, fRTHeightStorageClass),
Greg Daniela85e4bf2020-06-17 16:32:45 -04002023 out);
2024 this->writeWord(heightPtr, out);
2025 this->writeWord(fRTHeightStructId, out);
2026 this->writeWord(fieldIndexId, out);
2027 SpvId heightRead = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05002028 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fTypes.fFloat), heightRead,
Greg Daniela85e4bf2020-06-17 16:32:45 -04002029 heightPtr, out);
2030
2031 flippedYId = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05002032 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fTypes.fFloat), flippedYId,
Greg Daniela85e4bf2020-06-17 16:32:45 -04002033 heightRead, rawYId, out);
2034 }
2035
2036 // The z component will always be zero so we just get an id to the 0 literal
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002037 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002038 SpvId zeroId = writeFloatLiteral(zero);
Greg Daniela85e4bf2020-06-17 16:32:45 -04002039
Brian Osmane38bedd2020-12-21 11:51:54 -05002040 // Calculate the w component
Greg Daniela85e4bf2020-06-17 16:32:45 -04002041 SpvId rawWId = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05002042 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fTypes.fFloat),
2043 rawWId, result, 3, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04002044
2045 // Fill in the new fragcoord with the components from above
2046 SpvId adjusted = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002047 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
John Stiles54e7c052021-01-11 14:22:36 -05002048 this->writeWord(this->getType(*fContext.fTypes.fFloat4), out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04002049 this->writeWord(adjusted, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002050 this->writeWord(xId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04002051 if (fProgram.fSettings.fFlipY) {
2052 this->writeWord(flippedYId, out);
2053 } else {
2054 this->writeWord(rawYId, out);
2055 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002056 this->writeWord(zeroId, out);
Brian Osmane38bedd2020-12-21 11:51:54 -05002057 this->writeWord(rawWId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04002058
2059 return adjusted;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002060 }
Ethan Nicholas78686922020-10-08 06:46:27 -04002061 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
Chris Daltonb91c4662018-08-01 10:46:22 -06002062 !fProgram.fSettings.fFlipY) {
2063 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
2064 // the default convention of "counter-clockwise face is front".
2065 SpvId inverse = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05002066 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fTypes.fBool), inverse,
Chris Daltonb91c4662018-08-01 10:46:22 -06002067 result, out);
2068 return inverse;
2069 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002070 return result;
2071}
2072
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002073SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05002074 if (expr.base()->type().isVector()) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04002075 SpvId base = this->writeExpression(*expr.base(), out);
2076 SpvId index = this->writeExpression(*expr.index(), out);
Ethan Nicholasa9a06902019-01-07 14:42:40 -05002077 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002078 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.type()), result, base,
Ethan Nicholasa9a06902019-01-07 14:42:40 -05002079 index, out);
2080 return result;
2081 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002082 return getLValue(expr, out)->load(out);
2083}
2084
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002085SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002086 return getLValue(f, out)->load(out);
2087}
2088
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002089SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002090 SpvId base = this->writeExpression(*swizzle.base(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002091 SpvId result = this->nextId();
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002092 size_t count = swizzle.components().size();
ethannicholasb3058bd2016-07-01 08:22:01 -07002093 if (count == 1) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002094 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.type()), result, base,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002095 swizzle.components()[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002096 } else {
2097 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002098 this->writeWord(this->getType(swizzle.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002099 this->writeWord(result, out);
2100 this->writeWord(base, out);
Brian Osman25647672020-09-15 15:16:56 -04002101 this->writeWord(base, out);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002102 for (int component : swizzle.components()) {
Brian Osman25647672020-09-15 15:16:56 -04002103 this->writeWord(component, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002104 }
2105 }
2106 return result;
2107}
2108
Greg Daniel64773e62016-11-22 09:44:03 -05002109SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
2110 const Type& operandType, SpvId lhs,
2111 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002112 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002113 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002114 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002115 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002116 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002117 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002118 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002119 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
John Stiles123501f2020-12-09 10:08:13 -05002120 } else if (is_bool(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002121 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002122 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07002123 } else {
John Stiles123501f2020-12-09 10:08:13 -05002124 fErrors.error(operandType.fOffset,
2125 "unsupported operand for binary expression: " + operandType.description());
2126 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002127 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04002128 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002129 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
2130 fDecorationBuffer);
2131 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002132 return result;
2133}
2134
Ethan Nicholas48e24052018-03-14 13:51:39 -04002135SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
2136 OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05002137 if (operandType.isVector()) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002138 SpvId result = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05002139 this->writeInstruction(op, this->getType(*fContext.fTypes.fBool), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002140 return result;
2141 }
2142 return id;
2143}
2144
Ethan Nicholas68990be2017-07-13 09:36:52 -04002145SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
2146 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002147 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04002148 OutputStream& out) {
2149 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
John Stiles9aeed132020-11-24 17:36:06 -05002150 SkASSERT(operandType.isMatrix());
Ethan Nicholas0df21132018-07-10 09:37:51 -04002151 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2152 operandType.rows(),
2153 1));
John Stiles54e7c052021-01-11 14:22:36 -05002154 SpvId bvecType = this->getType(fContext.fTypes.fBool->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002155 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04002156 1));
John Stiles54e7c052021-01-11 14:22:36 -05002157 SpvId boolType = this->getType(*fContext.fTypes.fBool);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002158 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04002159 for (int i = 0; i < operandType.columns(); i++) {
2160 SpvId columnL = this->nextId();
2161 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2162 SpvId columnR = this->nextId();
2163 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002164 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002165 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
2166 SpvId merge = this->nextId();
2167 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002168 if (result != 0) {
2169 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002170 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002171 result = next;
2172 }
2173 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002174 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04002175 }
2176 }
2177 return result;
2178}
2179
Ethan Nicholas0df21132018-07-10 09:37:51 -04002180SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
2181 SpvId rhs, SpvOp_ floatOperator,
2182 SpvOp_ intOperator,
2183 OutputStream& out) {
2184 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
John Stiles9aeed132020-11-24 17:36:06 -05002185 SkASSERT(operandType.isMatrix());
Ethan Nicholas0df21132018-07-10 09:37:51 -04002186 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2187 operandType.rows(),
2188 1));
2189 SpvId columns[4];
2190 for (int i = 0; i < operandType.columns(); i++) {
2191 SpvId columnL = this->nextId();
2192 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2193 SpvId columnR = this->nextId();
2194 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2195 columns[i] = this->nextId();
2196 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2197 }
2198 SpvId result = this->nextId();
2199 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2200 this->writeWord(this->getType(operandType), out);
2201 this->writeWord(result, out);
2202 for (int i = 0; i < operandType.columns(); i++) {
2203 this->writeWord(columns[i], out);
2204 }
2205 return result;
2206}
2207
Ethan Nicholas49465b42019-04-17 12:22:21 -04002208std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2209 if (type.isInteger()) {
2210 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002211 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002212 else if (type.isFloat()) {
2213 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002214 } else {
Ethan Nicholase2c49992020-10-05 11:49:11 -04002215 ABORT("math is unsupported on type '%s'", String(type.name()).c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002216 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002217}
2218
2219SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Token::Kind op,
2220 const Type& rightType, SpvId rhs,
2221 const Type& resultType, OutputStream& out) {
John Stilesd0614f22020-12-09 11:11:41 -05002222 // The comma operator ignores the type of the left-hand side entirely.
2223 if (op == Token::Kind::TK_COMMA) {
2224 return rhs;
2225 }
Ethan Nicholas48e24052018-03-14 13:51:39 -04002226 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002227 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002228 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2229 // handling in SPIR-V
Ethan Nicholas49465b42019-04-17 12:22:21 -04002230 if (this->getActualType(leftType) != this->getActualType(rightType)) {
John Stiles9aeed132020-11-24 17:36:06 -05002231 if (leftType.isVector() && rightType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002232 if (op == Token::Kind::TK_SLASH) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002233 SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
2234 SpvId inverse = this->nextId();
2235 this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
2236 rhs = inverse;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002237 op = Token::Kind::TK_STAR;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002238 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002239 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002240 SpvId result = this->nextId();
2241 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2242 result, lhs, rhs, out);
2243 return result;
2244 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002245 // promote number to vector
2246 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002247 const Type& vecType = leftType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002248 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2249 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002250 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002251 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002252 this->writeWord(rhs, out);
2253 }
2254 rhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002255 operandType = &leftType;
John Stiles9aeed132020-11-24 17:36:06 -05002256 } else if (rightType.isVector() && leftType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002257 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002258 SpvId result = this->nextId();
2259 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2260 result, rhs, lhs, out);
2261 return result;
2262 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002263 // promote number to vector
2264 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002265 const Type& vecType = rightType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002266 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2267 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002268 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002269 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002270 this->writeWord(lhs, out);
2271 }
2272 lhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002273 operandType = &rightType;
John Stiles9aeed132020-11-24 17:36:06 -05002274 } else if (leftType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002275 SpvOp_ spvop;
John Stiles9aeed132020-11-24 17:36:06 -05002276 if (rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002277 spvop = SpvOpMatrixTimesMatrix;
John Stiles9aeed132020-11-24 17:36:06 -05002278 } else if (rightType.isVector()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002279 spvop = SpvOpMatrixTimesVector;
ethannicholasb3058bd2016-07-01 08:22:01 -07002280 } else {
John Stiles9aeed132020-11-24 17:36:06 -05002281 SkASSERT(rightType.isScalar());
Ethan Nicholas49465b42019-04-17 12:22:21 -04002282 spvop = SpvOpMatrixTimesScalar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002283 }
2284 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002285 this->writeInstruction(spvop, this->getType(resultType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002286 return result;
John Stiles9aeed132020-11-24 17:36:06 -05002287 } else if (rightType.isMatrix()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002288 SpvId result = this->nextId();
John Stiles9aeed132020-11-24 17:36:06 -05002289 if (leftType.isVector()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002290 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(resultType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002291 lhs, rhs, out);
2292 } else {
John Stiles9aeed132020-11-24 17:36:06 -05002293 SkASSERT(leftType.isScalar());
Ethan Nicholas49465b42019-04-17 12:22:21 -04002294 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(resultType), result,
2295 rhs, lhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002296 }
2297 return result;
2298 } else {
John Stilesd8ca6b62020-11-23 14:28:36 -05002299 fErrors.error(leftType.fOffset, "unsupported mixed-type expression");
Ethan Nicholas49465b42019-04-17 12:22:21 -04002300 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002301 }
2302 } else {
John Stiles2d4f9592020-10-30 10:29:12 -04002303 operandType = &this->getActualType(leftType);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002304 SkASSERT(*operandType == this->getActualType(rightType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002305 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002306 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002307 case Token::Kind::TK_EQEQ: {
John Stiles9aeed132020-11-24 17:36:06 -05002308 if (operandType->isMatrix()) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002309 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002310 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002311 }
John Stiles4a7dc462020-11-25 11:08:08 -05002312 SkASSERT(resultType.isBoolean());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002313 const Type* tmpType;
John Stiles9aeed132020-11-24 17:36:06 -05002314 if (operandType->isVector()) {
John Stiles54e7c052021-01-11 14:22:36 -05002315 tmpType = &fContext.fTypes.fBool->toCompound(fContext,
2316 operandType->columns(),
2317 operandType->rows());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002318 } else {
2319 tmpType = &resultType;
2320 }
2321 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002322 SpvOpFOrdEqual, SpvOpIEqual,
2323 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002324 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002325 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002326 case Token::Kind::TK_NEQ:
John Stiles9aeed132020-11-24 17:36:06 -05002327 if (operandType->isMatrix()) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002328 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002329 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002330 }
John Stiles4a7dc462020-11-25 11:08:08 -05002331 [[fallthrough]];
2332 case Token::Kind::TK_LOGICALXOR:
2333 SkASSERT(resultType.isBoolean());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002334 const Type* tmpType;
John Stiles9aeed132020-11-24 17:36:06 -05002335 if (operandType->isVector()) {
John Stiles54e7c052021-01-11 14:22:36 -05002336 tmpType = &fContext.fTypes.fBool->toCompound(fContext,
2337 operandType->columns(),
2338 operandType->rows());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002339 } else {
2340 tmpType = &resultType;
2341 }
2342 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002343 SpvOpFOrdNotEqual, SpvOpINotEqual,
2344 SpvOpINotEqual, SpvOpLogicalNotEqual,
2345 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002346 *operandType, SpvOpAny, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002347 case Token::Kind::TK_GT:
John Stiles4a7dc462020-11-25 11:08:08 -05002348 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002349 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2350 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002351 SpvOpUGreaterThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002352 case Token::Kind::TK_LT:
John Stiles4a7dc462020-11-25 11:08:08 -05002353 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002354 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002355 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002356 case Token::Kind::TK_GTEQ:
John Stiles4a7dc462020-11-25 11:08:08 -05002357 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002358 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2359 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002360 SpvOpUGreaterThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002361 case Token::Kind::TK_LTEQ:
John Stiles4a7dc462020-11-25 11:08:08 -05002362 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002363 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2364 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002365 SpvOpULessThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002366 case Token::Kind::TK_PLUS:
John Stiles9aeed132020-11-24 17:36:06 -05002367 if (leftType.isMatrix() && rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002368 SkASSERT(leftType == rightType);
2369 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002370 SpvOpFAdd, SpvOpIAdd, out);
2371 }
Greg Daniel64773e62016-11-22 09:44:03 -05002372 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002373 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002374 case Token::Kind::TK_MINUS:
John Stiles9aeed132020-11-24 17:36:06 -05002375 if (leftType.isMatrix() && rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002376 SkASSERT(leftType == rightType);
2377 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002378 SpvOpFSub, SpvOpISub, out);
2379 }
Greg Daniel64773e62016-11-22 09:44:03 -05002380 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002381 SpvOpISub, SpvOpISub, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002382 case Token::Kind::TK_STAR:
John Stiles9aeed132020-11-24 17:36:06 -05002383 if (leftType.isMatrix() && rightType.isMatrix()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002384 // matrix multiply
2385 SpvId result = this->nextId();
2386 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2387 lhs, rhs, out);
2388 return result;
2389 }
Greg Daniel64773e62016-11-22 09:44:03 -05002390 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002391 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002392 case Token::Kind::TK_SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002393 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002394 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002395 case Token::Kind::TK_PERCENT:
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002396 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2397 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002398 case Token::Kind::TK_SHL:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002399 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2400 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2401 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002402 case Token::Kind::TK_SHR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002403 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2404 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2405 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002406 case Token::Kind::TK_BITWISEAND:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002407 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2408 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002409 case Token::Kind::TK_BITWISEOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002410 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2411 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002412 case Token::Kind::TK_BITWISEXOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002413 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2414 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002415 default:
John Stiles5570c512020-11-19 17:58:07 -05002416 fErrors.error(0, "unsupported token");
Ethan Nicholas49465b42019-04-17 12:22:21 -04002417 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002418 }
2419}
2420
Ethan Nicholas49465b42019-04-17 12:22:21 -04002421SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
John Stiles2d4f9592020-10-30 10:29:12 -04002422 const Expression& left = *b.left();
2423 const Expression& right = *b.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002424 Token::Kind op = b.getOperator();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002425 // handle cases where we don't necessarily evaluate both LHS and RHS
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002426 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002427 case Token::Kind::TK_EQ: {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002428 SpvId rhs = this->writeExpression(right, out);
2429 this->getLValue(left, out)->store(rhs, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002430 return rhs;
2431 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002432 case Token::Kind::TK_LOGICALAND:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002433 return this->writeLogicalAnd(b, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002434 case Token::Kind::TK_LOGICALOR:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002435 return this->writeLogicalOr(b, out);
2436 default:
2437 break;
2438 }
2439
2440 std::unique_ptr<LValue> lvalue;
2441 SpvId lhs;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002442 if (Compiler::IsAssignment(op)) {
2443 lvalue = this->getLValue(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002444 lhs = lvalue->load(out);
2445 } else {
2446 lvalue = nullptr;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002447 lhs = this->writeExpression(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002448 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002449 SpvId rhs = this->writeExpression(right, out);
2450 SpvId result = this->writeBinaryExpression(left.type(), lhs, Compiler::RemoveAssignment(op),
2451 right.type(), rhs, b.type(), out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002452 if (lvalue) {
2453 lvalue->store(result, out);
2454 }
2455 return result;
2456}
2457
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002458SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002459 SkASSERT(a.getOperator() == Token::Kind::TK_LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002460 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002461 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
John Stiles2d4f9592020-10-30 10:29:12 -04002462 SpvId lhs = this->writeExpression(*a.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002463 SpvId rhsLabel = this->nextId();
2464 SpvId end = this->nextId();
2465 SpvId lhsBlock = fCurrentBlock;
2466 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2467 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2468 this->writeLabel(rhsLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04002469 SpvId rhs = this->writeExpression(*a.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002470 SpvId rhsBlock = fCurrentBlock;
2471 this->writeInstruction(SpvOpBranch, end, out);
2472 this->writeLabel(end, out);
2473 SpvId result = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05002474 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fTypes.fBool), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002475 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002476 return result;
2477}
2478
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002479SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002480 SkASSERT(o.getOperator() == Token::Kind::TK_LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002481 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002482 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
John Stiles2d4f9592020-10-30 10:29:12 -04002483 SpvId lhs = this->writeExpression(*o.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002484 SpvId rhsLabel = this->nextId();
2485 SpvId end = this->nextId();
2486 SpvId lhsBlock = fCurrentBlock;
2487 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2488 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2489 this->writeLabel(rhsLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04002490 SpvId rhs = this->writeExpression(*o.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002491 SpvId rhsBlock = fCurrentBlock;
2492 this->writeInstruction(SpvOpBranch, end, out);
2493 this->writeLabel(end, out);
2494 SpvId result = this->nextId();
John Stiles54e7c052021-01-11 14:22:36 -05002495 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fTypes.fBool), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002496 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002497 return result;
2498}
2499
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002500SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002501 const Type& type = t.type();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002502 SpvId test = this->writeExpression(*t.test(), out);
2503 if (t.ifTrue()->type().columns() == 1 &&
2504 t.ifTrue()->isCompileTimeConstant() &&
2505 t.ifFalse()->isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002506 // both true and false are constants, can just use OpSelect
2507 SpvId result = this->nextId();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002508 SpvId trueId = this->writeExpression(*t.ifTrue(), out);
2509 SpvId falseId = this->writeExpression(*t.ifFalse(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002510 this->writeInstruction(SpvOpSelect, this->getType(type), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002511 out);
2512 return result;
2513 }
Greg Daniel64773e62016-11-22 09:44:03 -05002514 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002515 // Adreno. Switched to storing the result in a temp variable as glslang does.
2516 SpvId var = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002517 this->writeInstruction(SpvOpVariable, this->getPointerType(type, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002518 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002519 SpvId trueLabel = this->nextId();
2520 SpvId falseLabel = this->nextId();
2521 SpvId end = this->nextId();
2522 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2523 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2524 this->writeLabel(trueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002525 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifTrue(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002526 this->writeInstruction(SpvOpBranch, end, out);
2527 this->writeLabel(falseLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002528 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifFalse(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002529 this->writeInstruction(SpvOpBranch, end, out);
2530 this->writeLabel(end, out);
2531 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002532 this->writeInstruction(SpvOpLoad, this->getType(type), result, var, out);
2533 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002534 return result;
2535}
2536
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002537SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002538 const Type& type = p.type();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002539 if (p.getOperator() == Token::Kind::TK_MINUS) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002540 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002541 SpvId typeId = this->getType(type);
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002542 SpvId expr = this->writeExpression(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002543 if (is_float(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002544 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002545 } else if (is_signed(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002546 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2547 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002548#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002549 ABORT("unsupported prefix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002550#endif
Brian Salomon23356442018-11-30 15:33:19 -05002551 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002552 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002553 return result;
2554 }
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002555 switch (p.getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002556 case Token::Kind::TK_PLUS:
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002557 return this->writeExpression(*p.operand(), out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002558 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002559 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002560 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
2561 SpvId result = this->writeBinaryOperation(type, type, lv->load(out), one,
Greg Daniel64773e62016-11-22 09:44:03 -05002562 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002563 out);
2564 lv->store(result, out);
2565 return result;
2566 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002567 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002568 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002569 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
2570 SpvId result = this->writeBinaryOperation(type, type, lv->load(out), one, SpvOpFSub,
2571 SpvOpISub, SpvOpISub, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002572 lv->store(result, out);
2573 return result;
2574 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002575 case Token::Kind::TK_LOGICALNOT: {
John Stiles4a7dc462020-11-25 11:08:08 -05002576 SkASSERT(p.operand()->type().isBoolean());
ethannicholasb3058bd2016-07-01 08:22:01 -07002577 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002578 this->writeInstruction(SpvOpLogicalNot, this->getType(type), result,
2579 this->writeExpression(*p.operand(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002580 return result;
2581 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002582 case Token::Kind::TK_BITWISENOT: {
ethannicholas5961bc92016-10-12 06:39:56 -07002583 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002584 this->writeInstruction(SpvOpNot, this->getType(type), result,
2585 this->writeExpression(*p.operand(), out), out);
ethannicholas5961bc92016-10-12 06:39:56 -07002586 return result;
2587 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002588 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002589#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002590 ABORT("unsupported prefix expression: %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002591#endif
2592 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002593 }
2594}
2595
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002596SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002597 const Type& type = p.type();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002598 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002599 SpvId result = lv->load(out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002600 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002601 switch (p.getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002602 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002603 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002604 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2605 lv->store(temp, out);
2606 return result;
2607 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002608 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002609 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002610 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2611 lv->store(temp, out);
2612 return result;
2613 }
2614 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002615#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002616 ABORT("unsupported postfix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002617#endif
2618 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002619 }
2620}
2621
ethannicholasf789b382016-08-03 12:43:36 -07002622SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
Ethan Nicholas59d660c2020-09-28 09:18:15 -04002623 if (b.value()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002624 if (fBoolTrue == 0) {
2625 fBoolTrue = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002626 this->writeInstruction(SpvOpConstantTrue, this->getType(b.type()), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002627 fConstantBuffer);
2628 }
2629 return fBoolTrue;
2630 } else {
2631 if (fBoolFalse == 0) {
2632 fBoolFalse = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002633 this->writeInstruction(SpvOpConstantFalse, this->getType(b.type()), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002634 fConstantBuffer);
2635 }
2636 return fBoolFalse;
2637 }
2638}
2639
ethannicholasf789b382016-08-03 12:43:36 -07002640SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
John Stilesbdc3d3c2021-01-06 18:41:40 -05002641 SPIRVNumberConstant key{i.value(), i.type().numberKind()};
John Stilesacb091f2021-01-06 11:57:58 -05002642 auto [iter, newlyCreated] = fNumberConstants.insert({key, (SpvId)-1});
2643 if (newlyCreated) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002644 SpvId result = this->nextId();
John Stilesacb091f2021-01-06 11:57:58 -05002645 this->writeInstruction(SpvOpConstant, this->getType(i.type()), result, (SpvId) i.value(),
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002646 fConstantBuffer);
John Stilesacb091f2021-01-06 11:57:58 -05002647 iter->second = result;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002648 }
John Stilesacb091f2021-01-06 11:57:58 -05002649 return iter->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002650}
2651
ethannicholasf789b382016-08-03 12:43:36 -07002652SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
John Stilesbdc3d3c2021-01-06 18:41:40 -05002653 // Convert the float literal into its bit-representation.
2654 float value = f.value();
2655 uint32_t valueBits;
2656 static_assert(sizeof(valueBits) == sizeof(value));
2657 memcpy(&valueBits, &value, sizeof(value));
2658
2659 SPIRVNumberConstant key{valueBits, f.type().numberKind()};
John Stilesacb091f2021-01-06 11:57:58 -05002660 auto [iter, newlyCreated] = fNumberConstants.insert({key, (SpvId)-1});
2661 if (newlyCreated) {
John Stiles8c578662020-06-01 15:32:47 +00002662 SpvId result = this->nextId();
John Stilesbdc3d3c2021-01-06 18:41:40 -05002663 this->writeInstruction(SpvOpConstant, this->getType(f.type()), result, (SpvId) valueBits,
John Stiles8c578662020-06-01 15:32:47 +00002664 fConstantBuffer);
John Stilesacb091f2021-01-06 11:57:58 -05002665 iter->second = result;
John Stiles8c578662020-06-01 15:32:47 +00002666 }
John Stilesacb091f2021-01-06 11:57:58 -05002667 return iter->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002668}
2669
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002670SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002671 SpvId result = fFunctionMap[&f];
Ethan Nicholased84b732020-10-08 11:45:44 -04002672 this->writeInstruction(SpvOpFunction, this->getType(f.returnType()), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002673 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04002674 this->writeInstruction(SpvOpName, result, f.name(), fNameBuffer);
Brian Osman5bf3e202020-10-13 10:34:18 -04002675 const std::vector<const Variable*>& parameters = f.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -04002676 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002677 SpvId id = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -04002678 fVariableMap[parameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002679 SpvId type;
Ethan Nicholased84b732020-10-08 11:45:44 -04002680 type = this->getPointerType(parameters[i]->type(), SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002681 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2682 }
2683 return result;
2684}
2685
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002686SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2687 fVariableBuffer.reset();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002688 SpvId result = this->writeFunctionStart(f.declaration(), out);
Ethan Nicholas7fb39362020-12-16 15:25:19 -05002689 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002690 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002691 StringStream bodyBuffer;
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002692 this->writeBlock((Block&) *f.body(), bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002693 write_stringstream(fVariableBuffer, out);
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002694 if (f.declaration().name() == "main") {
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002695 write_stringstream(fGlobalInitializersBuffer, out);
2696 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002697 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002698 if (fCurrentBlock) {
John Stiles54e7c052021-01-11 14:22:36 -05002699 if (f.declaration().returnType() == *fContext.fTypes.fVoid) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002700 this->writeInstruction(SpvOpReturn, out);
2701 } else {
2702 this->writeInstruction(SpvOpUnreachable, out);
2703 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002704 }
2705 this->writeInstruction(SpvOpFunctionEnd, out);
2706 return result;
2707}
2708
2709void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2710 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002711 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002712 fDecorationBuffer);
2713 }
2714 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002715 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002716 fDecorationBuffer);
2717 }
2718 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002719 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002720 fDecorationBuffer);
2721 }
2722 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002723 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002724 fDecorationBuffer);
2725 }
Greg Daniel64773e62016-11-22 09:44:03 -05002726 if (layout.fInputAttachmentIndex >= 0) {
2727 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2728 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002729 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002730 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002731 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002732 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002733 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002734 fDecorationBuffer);
2735 }
2736}
2737
2738void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2739 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002740 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002741 layout.fLocation, fDecorationBuffer);
2742 }
2743 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002744 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002745 layout.fBinding, fDecorationBuffer);
2746 }
2747 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002748 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002749 layout.fIndex, fDecorationBuffer);
2750 }
2751 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002752 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002753 layout.fSet, fDecorationBuffer);
2754 }
Greg Daniel64773e62016-11-22 09:44:03 -05002755 if (layout.fInputAttachmentIndex >= 0) {
2756 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2757 layout.fInputAttachmentIndex, fDecorationBuffer);
2758 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002759 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002760 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002761 layout.fBuiltin, fDecorationBuffer);
2762 }
2763}
2764
Ethan Nicholas81d15112018-07-13 12:48:50 -04002765static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2766 switch (m.fLayout.fPrimitive) {
2767 case Layout::kPoints_Primitive:
2768 *outSkInCount = 1;
2769 break;
2770 case Layout::kLines_Primitive:
2771 *outSkInCount = 2;
2772 break;
2773 case Layout::kLinesAdjacency_Primitive:
2774 *outSkInCount = 4;
2775 break;
2776 case Layout::kTriangles_Primitive:
2777 *outSkInCount = 3;
2778 break;
2779 case Layout::kTrianglesAdjacency_Primitive:
2780 *outSkInCount = 6;
2781 break;
2782 default:
2783 return;
2784 }
2785}
2786
Stephen White88574972020-06-23 19:09:29 -04002787SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf, bool appendRTHeight) {
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002788 bool isBuffer = ((intf.variable().modifiers().fFlags & Modifiers::kBuffer_Flag) != 0);
2789 bool pushConstant = ((intf.variable().modifiers().fLayout.fFlags &
2790 Layout::kPushConstant_Flag) != 0);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002791 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2792 MemoryLayout(MemoryLayout::k430_Standard) :
2793 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002794 SpvId result = this->nextId();
John Stilesad2d4942020-12-11 16:55:58 -05002795 std::unique_ptr<Type> rtHeightStructType;
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002796 const Type* type = &intf.variable().type();
John Stiles21f5f452020-11-30 09:57:59 -05002797 if (!MemoryLayout::LayoutIsSupported(*type)) {
John Stiles0023c0c2020-11-16 13:32:18 -05002798 fErrors.error(type->fOffset, "type '" + type->name() + "' is not permitted here");
2799 return this->nextId();
2800 }
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002801 Modifiers intfModifiers = intf.variable().modifiers();
2802 SpvStorageClass_ storageClass = get_storage_class(intfModifiers);
Stephen White88574972020-06-23 19:09:29 -04002803 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Greg Daniele6ab9982018-08-22 13:56:32 +00002804 SkASSERT(fRTHeightStructId == (SpvId) -1);
2805 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002806 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002807 fRTHeightStructId = result;
2808 fRTHeightFieldIndex = fields.size();
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002809 fRTHeightStorageClass = storageClass;
John Stilesad2d4942020-12-11 16:55:58 -05002810 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME),
John Stiles54e7c052021-01-11 14:22:36 -05002811 fContext.fTypes.fFloat.get());
John Stilesad2d4942020-12-11 16:55:58 -05002812 rtHeightStructType = Type::MakeStructType(type->fOffset, type->name(), std::move(fields));
2813 type = rtHeightStructType.get();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002814 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002815 SpvId typeId;
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002816 if (intfModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osman133724c2020-10-28 14:14:39 -04002817 for (const ProgramElement* e : fProgram.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04002818 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04002819 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholas81d15112018-07-13 12:48:50 -04002820 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002821 }
2822 }
John Stilesad2d4942020-12-11 16:55:58 -05002823 typeId = this->getType(
2824 *Type::MakeArrayType("sk_in", intf.variable().type().componentType(), fSkInCount),
2825 memoryLayout);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002826 } else {
2827 typeId = this->getType(*type, memoryLayout);
2828 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002829 if (intfModifiers.fFlags & Modifiers::kBuffer_Flag) {
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002830 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002831 } else if (intfModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002832 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002833 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002834 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002835 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002836 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002837 Layout layout = intfModifiers.fLayout;
2838 if (intfModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002839 layout.fSet = 0;
2840 }
2841 this->writeLayout(layout, result);
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002842 fVariableMap[&intf.variable()] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002843 return result;
2844}
2845
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002846void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002847 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2848}
2849
2850void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2851 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002852 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2853 }
2854}
2855
Brian Osman010ce6a2020-10-19 16:34:10 -04002856bool is_dead(const Variable& var, const ProgramUsage* usage) {
2857 ProgramUsage::VariableCounts counts = usage->get(var);
2858 if (counts.fRead || counts.fWrite) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002859 return false;
2860 }
2861 // not entirely sure what the rules are for when it's safe to elide interface variables, but it
2862 // causes various problems to elide some of them even when dead. But it also causes problems
2863 // *not* to elide sk_SampleMask when it's not being used.
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002864 if (!(var.modifiers().fFlags & (Modifiers::kIn_Flag |
2865 Modifiers::kOut_Flag |
2866 Modifiers::kUniform_Flag |
2867 Modifiers::kBuffer_Flag))) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002868 return true;
2869 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002870 return var.modifiers().fLayout.fBuiltin == SK_SAMPLEMASK_BUILTIN;
Chris Dalton2284aab2019-11-15 11:02:24 -07002871}
2872
ethannicholas5961bc92016-10-12 06:39:56 -07002873#define BUILTIN_IGNORE 9999
Brian Osmanc0213602020-10-06 14:43:32 -04002874void SPIRVCodeGenerator::writeGlobalVar(Program::Kind kind, const VarDeclaration& varDecl,
2875 OutputStream& out) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002876 const Variable& var = varDecl.var();
Brian Osmanc0213602020-10-06 14:43:32 -04002877 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2878 // in the OpenGL backend.
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002879 SkASSERT(!(var.modifiers().fFlags & (Modifiers::kReadOnly_Flag |
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002880 Modifiers::kWriteOnly_Flag |
2881 Modifiers::kCoherent_Flag |
2882 Modifiers::kVolatile_Flag |
2883 Modifiers::kRestrict_Flag)));
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002884 if (var.modifiers().fLayout.fBuiltin == BUILTIN_IGNORE) {
Brian Osmanc0213602020-10-06 14:43:32 -04002885 return;
2886 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002887 if (var.modifiers().fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
Brian Osmanc0213602020-10-06 14:43:32 -04002888 kind != Program::kFragment_Kind) {
2889 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
2890 return;
2891 }
Brian Osman010ce6a2020-10-19 16:34:10 -04002892 if (is_dead(var, fProgram.fUsage.get())) {
Brian Osmanc0213602020-10-06 14:43:32 -04002893 return;
2894 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002895 const Type& type = var.type();
Brian Osmanc0213602020-10-06 14:43:32 -04002896 SpvStorageClass_ storageClass;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002897 if (var.modifiers().fFlags & Modifiers::kIn_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002898 storageClass = SpvStorageClassInput;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002899 } else if (var.modifiers().fFlags & Modifiers::kOut_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002900 storageClass = SpvStorageClassOutput;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002901 } else if (var.modifiers().fFlags & Modifiers::kUniform_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002902 if (type.typeKind() == Type::TypeKind::kSampler ||
2903 type.typeKind() == Type::TypeKind::kSeparateSampler ||
2904 type.typeKind() == Type::TypeKind::kTexture) {
2905 storageClass = SpvStorageClassUniformConstant;
ethannicholasb3058bd2016-07-01 08:22:01 -07002906 } else {
Brian Osmanc0213602020-10-06 14:43:32 -04002907 storageClass = SpvStorageClassUniform;
ethannicholasb3058bd2016-07-01 08:22:01 -07002908 }
Brian Osmanc0213602020-10-06 14:43:32 -04002909 } else {
2910 storageClass = SpvStorageClassPrivate;
2911 }
2912 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002913 fVariableMap[&var] = id;
Brian Osmanc0213602020-10-06 14:43:32 -04002914 SpvId typeId;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002915 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osmanc0213602020-10-06 14:43:32 -04002916 typeId = this->getPointerType(
John Stilesad2d4942020-12-11 16:55:58 -05002917 *Type::MakeArrayType("sk_in", type.componentType(), fSkInCount),
Brian Osmanc0213602020-10-06 14:43:32 -04002918 storageClass);
2919 } else {
2920 typeId = this->getPointerType(type, storageClass);
2921 }
2922 this->writeInstruction(SpvOpVariable, typeId, id, storageClass, fConstantBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002923 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002924 this->writePrecisionModifier(type, id);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002925 if (varDecl.value()) {
Brian Osmanc0213602020-10-06 14:43:32 -04002926 SkASSERT(!fCurrentBlock);
2927 fCurrentBlock = -1;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002928 SpvId value = this->writeExpression(*varDecl.value(), fGlobalInitializersBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002929 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
2930 fCurrentBlock = 0;
2931 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002932 this->writeLayout(var.modifiers().fLayout, id);
2933 if (var.modifiers().fFlags & Modifiers::kFlat_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002934 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2935 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002936 if (var.modifiers().fFlags & Modifiers::kNoPerspective_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002937 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2938 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002939 }
2940}
2941
Brian Osmanc0213602020-10-06 14:43:32 -04002942void SPIRVCodeGenerator::writeVarDeclaration(const VarDeclaration& varDecl, OutputStream& out) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002943 const Variable& var = varDecl.var();
Brian Osmanc0213602020-10-06 14:43:32 -04002944 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2945 // in the OpenGL backend.
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002946 SkASSERT(!(var.modifiers().fFlags & (Modifiers::kReadOnly_Flag |
2947 Modifiers::kWriteOnly_Flag |
2948 Modifiers::kCoherent_Flag |
2949 Modifiers::kVolatile_Flag |
2950 Modifiers::kRestrict_Flag)));
Brian Osmanc0213602020-10-06 14:43:32 -04002951 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002952 fVariableMap[&var] = id;
2953 SpvId type = this->getPointerType(var.type(), SpvStorageClassFunction);
Brian Osmanc0213602020-10-06 14:43:32 -04002954 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002955 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
2956 if (varDecl.value()) {
2957 SpvId value = this->writeExpression(*varDecl.value(), out);
Brian Osmanc0213602020-10-06 14:43:32 -04002958 this->writeInstruction(SpvOpStore, id, value, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002959 }
2960}
2961
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002962void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002963 switch (s.kind()) {
John Stiles98c1f822020-09-09 14:18:53 -04002964 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04002965 case Statement::Kind::kNop:
Ethan Nicholascb670962017-04-20 19:31:52 -04002966 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002967 case Statement::Kind::kBlock:
ethannicholasb3058bd2016-07-01 08:22:01 -07002968 this->writeBlock((Block&) s, out);
2969 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002970 case Statement::Kind::kExpression:
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04002971 this->writeExpression(*s.as<ExpressionStatement>().expression(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002972 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002973 case Statement::Kind::kReturn:
John Stiles26f98502020-08-18 09:30:51 -04002974 this->writeReturnStatement(s.as<ReturnStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002975 break;
Brian Osmanc0213602020-10-06 14:43:32 -04002976 case Statement::Kind::kVarDeclaration:
2977 this->writeVarDeclaration(s.as<VarDeclaration>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002978 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002979 case Statement::Kind::kIf:
John Stiles26f98502020-08-18 09:30:51 -04002980 this->writeIfStatement(s.as<IfStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002981 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002982 case Statement::Kind::kFor:
John Stiles26f98502020-08-18 09:30:51 -04002983 this->writeForStatement(s.as<ForStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002984 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002985 case Statement::Kind::kDo:
John Stiles26f98502020-08-18 09:30:51 -04002986 this->writeDoStatement(s.as<DoStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002987 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002988 case Statement::Kind::kSwitch:
John Stiles26f98502020-08-18 09:30:51 -04002989 this->writeSwitchStatement(s.as<SwitchStatement>(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002990 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002991 case Statement::Kind::kBreak:
ethannicholasb3058bd2016-07-01 08:22:01 -07002992 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2993 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002994 case Statement::Kind::kContinue:
ethannicholasb3058bd2016-07-01 08:22:01 -07002995 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2996 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002997 case Statement::Kind::kDiscard:
ethannicholasb3058bd2016-07-01 08:22:01 -07002998 this->writeInstruction(SpvOpKill, out);
2999 break;
3000 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05003001#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07003002 ABORT("unsupported statement: %s", s.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05003003#endif
3004 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003005 }
3006}
3007
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003008void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04003009 for (const std::unique_ptr<Statement>& stmt : b.children()) {
3010 this->writeStatement(*stmt, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003011 }
3012}
3013
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003014void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04003015 SpvId test = this->writeExpression(*stmt.test(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003016 SpvId ifTrue = this->nextId();
3017 SpvId ifFalse = this->nextId();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04003018 if (stmt.ifFalse()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003019 SpvId end = this->nextId();
3020 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3021 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
3022 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04003023 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003024 if (fCurrentBlock) {
3025 this->writeInstruction(SpvOpBranch, end, out);
3026 }
3027 this->writeLabel(ifFalse, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04003028 this->writeStatement(*stmt.ifFalse(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003029 if (fCurrentBlock) {
3030 this->writeInstruction(SpvOpBranch, end, out);
3031 }
3032 this->writeLabel(end, out);
3033 } else {
3034 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
3035 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
3036 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04003037 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003038 if (fCurrentBlock) {
3039 this->writeInstruction(SpvOpBranch, ifFalse, out);
3040 }
3041 this->writeLabel(ifFalse, out);
3042 }
3043}
3044
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003045void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003046 if (f.initializer()) {
3047 this->writeStatement(*f.initializer(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003048 }
3049 SpvId header = this->nextId();
3050 SpvId start = this->nextId();
3051 SpvId body = this->nextId();
3052 SpvId next = this->nextId();
3053 fContinueTarget.push(next);
3054 SpvId end = this->nextId();
3055 fBreakTarget.push(end);
3056 this->writeInstruction(SpvOpBranch, header, out);
3057 this->writeLabel(header, out);
3058 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07003059 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003060 this->writeLabel(start, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003061 if (f.test()) {
3062 SpvId test = this->writeExpression(*f.test(), out);
ethannicholas22f939e2016-10-13 13:25:34 -07003063 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
Ethan Nicholas7fb39362020-12-16 15:25:19 -05003064 } else {
3065 this->writeInstruction(SpvOpBranch, body, out);
ethannicholas22f939e2016-10-13 13:25:34 -07003066 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003067 this->writeLabel(body, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003068 this->writeStatement(*f.statement(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003069 if (fCurrentBlock) {
3070 this->writeInstruction(SpvOpBranch, next, out);
3071 }
3072 this->writeLabel(next, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003073 if (f.next()) {
3074 this->writeExpression(*f.next(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003075 }
3076 this->writeInstruction(SpvOpBranch, header, out);
3077 this->writeLabel(end, out);
3078 fBreakTarget.pop();
3079 fContinueTarget.pop();
3080}
3081
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003082void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003083 SpvId header = this->nextId();
3084 SpvId start = this->nextId();
3085 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003086 SpvId continueTarget = this->nextId();
3087 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003088 SpvId end = this->nextId();
3089 fBreakTarget.push(end);
3090 this->writeInstruction(SpvOpBranch, header, out);
3091 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003092 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003093 this->writeInstruction(SpvOpBranch, start, out);
3094 this->writeLabel(start, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003095 this->writeStatement(*d.statement(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003096 if (fCurrentBlock) {
3097 this->writeInstruction(SpvOpBranch, next, out);
3098 }
3099 this->writeLabel(next, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003100 SpvId test = this->writeExpression(*d.test(), out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003101 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
3102 this->writeLabel(continueTarget, out);
3103 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003104 this->writeLabel(end, out);
3105 fBreakTarget.pop();
3106 fContinueTarget.pop();
3107}
3108
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003109void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04003110 SpvId value = this->writeExpression(*s.value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003111 std::vector<SpvId> labels;
3112 SpvId end = this->nextId();
3113 SpvId defaultLabel = end;
3114 fBreakTarget.push(end);
3115 int size = 3;
John Stiles2d4f9592020-10-30 10:29:12 -04003116 auto& cases = s.cases();
3117 for (const std::unique_ptr<SwitchCase>& c : cases) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003118 SpvId label = this->nextId();
3119 labels.push_back(label);
John Stiles2d4f9592020-10-30 10:29:12 -04003120 if (c->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003121 size += 2;
3122 } else {
3123 defaultLabel = label;
3124 }
3125 }
3126 labels.push_back(end);
3127 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3128 this->writeOpCode(SpvOpSwitch, size, out);
3129 this->writeWord(value, out);
3130 this->writeWord(defaultLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04003131 for (size_t i = 0; i < cases.size(); ++i) {
3132 if (!cases[i]->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003133 continue;
3134 }
John Stiles2d4f9592020-10-30 10:29:12 -04003135 this->writeWord(cases[i]->value()->as<IntLiteral>().value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003136 this->writeWord(labels[i], out);
3137 }
John Stiles2d4f9592020-10-30 10:29:12 -04003138 for (size_t i = 0; i < cases.size(); ++i) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003139 this->writeLabel(labels[i], out);
John Stiles2d4f9592020-10-30 10:29:12 -04003140 for (const auto& stmt : cases[i]->statements()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003141 this->writeStatement(*stmt, out);
3142 }
3143 if (fCurrentBlock) {
3144 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3145 }
3146 }
3147 this->writeLabel(end, out);
3148 fBreakTarget.pop();
3149}
3150
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003151void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003152 if (r.expression()) {
3153 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.expression(), out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003154 out);
3155 } else {
3156 this->writeInstruction(SpvOpReturn, out);
3157 }
3158}
3159
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003160void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003161 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003162 int invocations = 1;
Brian Osman133724c2020-10-28 14:14:39 -04003163 for (const ProgramElement* e : fProgram.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003164 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04003165 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003166 if (m.fFlags & Modifiers::kIn_Flag) {
3167 if (m.fLayout.fInvocations != -1) {
3168 invocations = m.fLayout.fInvocations;
3169 }
3170 SpvId input;
3171 switch (m.fLayout.fPrimitive) {
3172 case Layout::kPoints_Primitive:
3173 input = SpvExecutionModeInputPoints;
3174 break;
3175 case Layout::kLines_Primitive:
3176 input = SpvExecutionModeInputLines;
3177 break;
3178 case Layout::kLinesAdjacency_Primitive:
3179 input = SpvExecutionModeInputLinesAdjacency;
3180 break;
3181 case Layout::kTriangles_Primitive:
3182 input = SpvExecutionModeTriangles;
3183 break;
3184 case Layout::kTrianglesAdjacency_Primitive:
3185 input = SpvExecutionModeInputTrianglesAdjacency;
3186 break;
3187 default:
3188 input = 0;
3189 break;
3190 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003191 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003192 if (input) {
3193 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3194 }
3195 } else if (m.fFlags & Modifiers::kOut_Flag) {
3196 SpvId output;
3197 switch (m.fLayout.fPrimitive) {
3198 case Layout::kPoints_Primitive:
3199 output = SpvExecutionModeOutputPoints;
3200 break;
3201 case Layout::kLineStrip_Primitive:
3202 output = SpvExecutionModeOutputLineStrip;
3203 break;
3204 case Layout::kTriangleStrip_Primitive:
3205 output = SpvExecutionModeOutputTriangleStrip;
3206 break;
3207 default:
3208 output = 0;
3209 break;
3210 }
3211 if (output) {
3212 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3213 }
3214 if (m.fLayout.fMaxVertices != -1) {
3215 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3216 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3217 out);
3218 }
3219 }
3220 }
3221 }
3222 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3223 invocations, out);
3224}
3225
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003226void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003227 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003228 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003229 std::set<SpvId> interfaceVars;
Brian Osman1f8f5752020-10-28 14:46:21 -04003230 // assign IDs to functions
Brian Osman133724c2020-10-28 14:14:39 -04003231 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003232 switch (e->kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04003233 case ProgramElement::Kind::kFunction: {
Brian Osman1179fcf2020-10-08 16:04:40 -04003234 const FunctionDefinition& f = e->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04003235 fFunctionMap[&f.declaration()] = this->nextId();
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003236 break;
3237 }
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003238 default:
3239 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003240 }
3241 }
Brian Osman133724c2020-10-28 14:14:39 -04003242 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003243 if (e->is<InterfaceBlock>()) {
Brian Osman1f8f5752020-10-28 14:46:21 -04003244 const InterfaceBlock& intf = e->as<InterfaceBlock>();
ethannicholasb3058bd2016-07-01 08:22:01 -07003245 SpvId id = this->writeInterfaceBlock(intf);
Brian Osman1f8f5752020-10-28 14:46:21 -04003246
3247 const Modifiers& modifiers = intf.variable().modifiers();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003248 if (((modifiers.fFlags & Modifiers::kIn_Flag) ||
3249 (modifiers.fFlags & Modifiers::kOut_Flag)) &&
3250 modifiers.fLayout.fBuiltin == -1 &&
Brian Osman010ce6a2020-10-19 16:34:10 -04003251 !is_dead(intf.variable(), fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003252 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003253 }
3254 }
3255 }
Brian Osman133724c2020-10-28 14:14:39 -04003256 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003257 if (e->is<GlobalVarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04003258 this->writeGlobalVar(program.fKind,
3259 e->as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>(),
3260 body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003261 }
3262 }
Brian Osman133724c2020-10-28 14:14:39 -04003263 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003264 if (e->is<FunctionDefinition>()) {
3265 this->writeFunction(e->as<FunctionDefinition>(), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003266 }
3267 }
ethannicholasd598f792016-07-25 10:08:54 -07003268 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003269 for (auto entry : fFunctionMap) {
Ethan Nicholase2c49992020-10-05 11:49:11 -04003270 if (entry.first->name() == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003271 main = entry.first;
3272 }
3273 }
Ethan Nicholas1a668d22019-04-18 10:37:40 -04003274 if (!main) {
3275 fErrors.error(0, "program does not contain a main() function");
3276 return;
3277 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003278 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003279 const Variable* var = entry.first;
Ethan Nicholas453f67f2020-10-09 10:43:45 -04003280 if (var->storage() == Variable::Storage::kGlobal &&
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003281 ((var->modifiers().fFlags & Modifiers::kIn_Flag) ||
Brian Osman010ce6a2020-10-19 16:34:10 -04003282 (var->modifiers().fFlags & Modifiers::kOut_Flag)) &&
3283 !is_dead(*var, fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003284 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003285 }
3286 }
3287 this->writeCapabilities(out);
3288 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3289 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003290 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->name().fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003291 (int32_t) interfaceVars.size(), out);
3292 switch (program.fKind) {
3293 case Program::kVertex_Kind:
3294 this->writeWord(SpvExecutionModelVertex, out);
3295 break;
3296 case Program::kFragment_Kind:
3297 this->writeWord(SpvExecutionModelFragment, out);
3298 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003299 case Program::kGeometry_Kind:
3300 this->writeWord(SpvExecutionModelGeometry, out);
3301 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003302 default:
3303 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003304 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003305 SpvId entryPoint = fFunctionMap[main];
3306 this->writeWord(entryPoint, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003307 this->writeString(main->name().fChars, main->name().fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003308 for (int var : interfaceVars) {
3309 this->writeWord(var, out);
3310 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003311 if (program.fKind == Program::kGeometry_Kind) {
3312 this->writeGeometryShaderExecutionMode(entryPoint, out);
3313 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003314 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003315 this->writeInstruction(SpvOpExecutionMode,
3316 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003317 SpvExecutionModeOriginUpperLeft,
3318 out);
3319 }
Brian Osman133724c2020-10-28 14:14:39 -04003320 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003321 if (e->is<Extension>()) {
3322 this->writeInstruction(SpvOpSourceExtension, e->as<Extension>().name().c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003323 }
3324 }
Greg Daniel64773e62016-11-22 09:44:03 -05003325
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003326 write_stringstream(fExtraGlobalsBuffer, out);
3327 write_stringstream(fNameBuffer, out);
3328 write_stringstream(fDecorationBuffer, out);
3329 write_stringstream(fConstantBuffer, out);
3330 write_stringstream(fExternalFunctionsBuffer, out);
3331 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003332}
3333
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003334bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003335 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003336 this->writeWord(SpvMagicNumber, *fOut);
3337 this->writeWord(SpvVersion, *fOut);
3338 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003339 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003340 this->writeInstructions(fProgram, buffer);
3341 this->writeWord(fIdCount, *fOut);
3342 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003343 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003344 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003345}
3346
John Stilesa6841be2020-08-06 14:11:56 -04003347} // namespace SkSL