blob: 5e68c18d5305839a010e50f8bd28e54dcc3b4093 [file] [log] [blame]
ethannicholasb3058bd2016-07-01 08:22:01 -07001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
Ethan Nicholasbcf35f82017-03-30 18:42:48 +00007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/sksl/SkSLSPIRVCodeGenerator.h"
Ethan Nicholas9bd301d2017-03-31 16:04:34 +00009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "src/sksl/GLSL.std.450.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070011
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "src/sksl/SkSLCompiler.h"
13#include "src/sksl/ir/SkSLExpressionStatement.h"
14#include "src/sksl/ir/SkSLExtension.h"
15#include "src/sksl/ir/SkSLIndexExpression.h"
16#include "src/sksl/ir/SkSLVariableReference.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070017
Ethan Nicholas0be34802019-08-15 12:36:58 -040018#ifdef SK_VULKAN
19#include "src/gpu/vk/GrVkCaps.h"
20#endif
21
ethannicholasb3058bd2016-07-01 08:22:01 -070022namespace SkSL {
23
ethannicholasb3058bd2016-07-01 08:22:01 -070024static const int32_t SKSL_MAGIC = 0x0; // FIXME: we should probably register a magic number
25
26void SPIRVCodeGenerator::setupIntrinsics() {
27#define ALL_GLSL(x) std::make_tuple(kGLSL_STD_450_IntrinsicKind, GLSLstd450 ## x, GLSLstd450 ## x, \
28 GLSLstd450 ## x, GLSLstd450 ## x)
29#define BY_TYPE_GLSL(ifFloat, ifInt, ifUInt) std::make_tuple(kGLSL_STD_450_IntrinsicKind, \
30 GLSLstd450 ## ifFloat, \
31 GLSLstd450 ## ifInt, \
32 GLSLstd450 ## ifUInt, \
33 SpvOpUndef)
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040034#define ALL_SPIRV(x) std::make_tuple(kSPIRV_IntrinsicKind, SpvOp ## x, SpvOp ## x, SpvOp ## x, \
35 SpvOp ## x)
ethannicholasb3058bd2016-07-01 08:22:01 -070036#define SPECIAL(x) std::make_tuple(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic, \
37 k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
38 k ## x ## _SpecialIntrinsic)
Ethan Nicholas0df1b042017-03-31 13:56:23 -040039 fIntrinsicMap[String("round")] = ALL_GLSL(Round);
40 fIntrinsicMap[String("roundEven")] = ALL_GLSL(RoundEven);
41 fIntrinsicMap[String("trunc")] = ALL_GLSL(Trunc);
42 fIntrinsicMap[String("abs")] = BY_TYPE_GLSL(FAbs, SAbs, SAbs);
43 fIntrinsicMap[String("sign")] = BY_TYPE_GLSL(FSign, SSign, SSign);
44 fIntrinsicMap[String("floor")] = ALL_GLSL(Floor);
45 fIntrinsicMap[String("ceil")] = ALL_GLSL(Ceil);
46 fIntrinsicMap[String("fract")] = ALL_GLSL(Fract);
47 fIntrinsicMap[String("radians")] = ALL_GLSL(Radians);
48 fIntrinsicMap[String("degrees")] = ALL_GLSL(Degrees);
49 fIntrinsicMap[String("sin")] = ALL_GLSL(Sin);
50 fIntrinsicMap[String("cos")] = ALL_GLSL(Cos);
51 fIntrinsicMap[String("tan")] = ALL_GLSL(Tan);
52 fIntrinsicMap[String("asin")] = ALL_GLSL(Asin);
53 fIntrinsicMap[String("acos")] = ALL_GLSL(Acos);
54 fIntrinsicMap[String("atan")] = SPECIAL(Atan);
55 fIntrinsicMap[String("sinh")] = ALL_GLSL(Sinh);
56 fIntrinsicMap[String("cosh")] = ALL_GLSL(Cosh);
57 fIntrinsicMap[String("tanh")] = ALL_GLSL(Tanh);
58 fIntrinsicMap[String("asinh")] = ALL_GLSL(Asinh);
59 fIntrinsicMap[String("acosh")] = ALL_GLSL(Acosh);
60 fIntrinsicMap[String("atanh")] = ALL_GLSL(Atanh);
61 fIntrinsicMap[String("pow")] = ALL_GLSL(Pow);
62 fIntrinsicMap[String("exp")] = ALL_GLSL(Exp);
63 fIntrinsicMap[String("log")] = ALL_GLSL(Log);
64 fIntrinsicMap[String("exp2")] = ALL_GLSL(Exp2);
65 fIntrinsicMap[String("log2")] = ALL_GLSL(Log2);
66 fIntrinsicMap[String("sqrt")] = ALL_GLSL(Sqrt);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -040067 fIntrinsicMap[String("inverse")] = ALL_GLSL(MatrixInverse);
68 fIntrinsicMap[String("transpose")] = ALL_SPIRV(Transpose);
John Stiles3679cd12020-12-09 16:22:12 -050069 fIntrinsicMap[String("isinf")] = ALL_SPIRV(IsInf);
70 fIntrinsicMap[String("isnan")] = ALL_SPIRV(IsNan);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040071 fIntrinsicMap[String("inversesqrt")] = ALL_GLSL(InverseSqrt);
72 fIntrinsicMap[String("determinant")] = ALL_GLSL(Determinant);
73 fIntrinsicMap[String("matrixInverse")] = ALL_GLSL(MatrixInverse);
Ethan Nicholas70a44b22017-11-30 09:09:16 -050074 fIntrinsicMap[String("mod")] = SPECIAL(Mod);
John Stiles01957272020-12-09 17:14:47 -050075 fIntrinsicMap[String("modf")] = ALL_GLSL(Modf);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050076 fIntrinsicMap[String("min")] = SPECIAL(Min);
77 fIntrinsicMap[String("max")] = SPECIAL(Max);
78 fIntrinsicMap[String("clamp")] = SPECIAL(Clamp);
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040079 fIntrinsicMap[String("saturate")] = SPECIAL(Saturate);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040080 fIntrinsicMap[String("dot")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
Ethan Nicholas0187ae62017-05-03 11:03:44 -040081 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050082 fIntrinsicMap[String("mix")] = SPECIAL(Mix);
Brian Osman6ba3be12020-11-13 16:32:52 -050083 fIntrinsicMap[String("step")] = SPECIAL(Step);
84 fIntrinsicMap[String("smoothstep")] = SPECIAL(SmoothStep);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040085 fIntrinsicMap[String("fma")] = ALL_GLSL(Fma);
86 fIntrinsicMap[String("frexp")] = ALL_GLSL(Frexp);
87 fIntrinsicMap[String("ldexp")] = ALL_GLSL(Ldexp);
ethannicholasb3058bd2016-07-01 08:22:01 -070088
Ethan Nicholas0df1b042017-03-31 13:56:23 -040089#define PACK(type) fIntrinsicMap[String("pack" #type)] = ALL_GLSL(Pack ## type); \
90 fIntrinsicMap[String("unpack" #type)] = ALL_GLSL(Unpack ## type)
ethannicholasb3058bd2016-07-01 08:22:01 -070091 PACK(Snorm4x8);
92 PACK(Unorm4x8);
93 PACK(Snorm2x16);
94 PACK(Unorm2x16);
95 PACK(Half2x16);
96 PACK(Double2x32);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040097 fIntrinsicMap[String("length")] = ALL_GLSL(Length);
98 fIntrinsicMap[String("distance")] = ALL_GLSL(Distance);
99 fIntrinsicMap[String("cross")] = ALL_GLSL(Cross);
100 fIntrinsicMap[String("normalize")] = ALL_GLSL(Normalize);
101 fIntrinsicMap[String("faceForward")] = ALL_GLSL(FaceForward);
102 fIntrinsicMap[String("reflect")] = ALL_GLSL(Reflect);
103 fIntrinsicMap[String("refract")] = ALL_GLSL(Refract);
104 fIntrinsicMap[String("findLSB")] = ALL_GLSL(FindILsb);
105 fIntrinsicMap[String("findMSB")] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
106 fIntrinsicMap[String("dFdx")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400107 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700108 fIntrinsicMap[String("dFdy")] = SPECIAL(DFdy);
Chris Dalton09212192018-11-13 15:07:24 -0500109 fIntrinsicMap[String("fwidth")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFwidth,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400110 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400111 fIntrinsicMap[String("makeSampler2D")] = SPECIAL(SampledImage);
112
Ethan Nicholas13863662019-07-29 13:05:15 -0400113 fIntrinsicMap[String("sample")] = SPECIAL(Texture);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400114 fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
Greg Daniel64773e62016-11-22 09:44:03 -0500115
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400116 fIntrinsicMap[String("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400117 SpvOpUndef, SpvOpUndef, SpvOpAny);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400118 fIntrinsicMap[String("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400119 SpvOpUndef, SpvOpUndef, SpvOpAll);
Brian Osman540c13a2020-11-24 16:55:34 -0500120 fIntrinsicMap[String("not")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
121 SpvOpUndef, SpvOpUndef,
122 SpvOpLogicalNot);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400123 fIntrinsicMap[String("equal")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400124 SpvOpFOrdEqual, SpvOpIEqual,
125 SpvOpIEqual, SpvOpLogicalEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400126 fIntrinsicMap[String("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400127 SpvOpFOrdNotEqual, SpvOpINotEqual,
128 SpvOpINotEqual,
129 SpvOpLogicalNotEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400130 fIntrinsicMap[String("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500131 SpvOpFOrdLessThan, SpvOpSLessThan,
132 SpvOpULessThan, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400133 fIntrinsicMap[String("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500134 SpvOpFOrdLessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400135 SpvOpSLessThanEqual,
136 SpvOpULessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400137 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400138 fIntrinsicMap[String("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500139 SpvOpFOrdGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400140 SpvOpSGreaterThan,
141 SpvOpUGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400142 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400143 fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500144 SpvOpFOrdGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400145 SpvOpSGreaterThanEqual,
146 SpvOpUGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400147 SpvOpUndef);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400148 fIntrinsicMap[String("EmitVertex")] = ALL_SPIRV(EmitVertex);
149 fIntrinsicMap[String("EndPrimitive")] = ALL_SPIRV(EndPrimitive);
ethannicholasb3058bd2016-07-01 08:22:01 -0700150// interpolateAt* not yet supported...
151}
152
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400153void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700154 out.write((const char*) &word, sizeof(word));
ethannicholasb3058bd2016-07-01 08:22:01 -0700155}
156
ethannicholasd598f792016-07-25 10:08:54 -0700157static bool is_float(const Context& context, const Type& type) {
Ethan Nicholas0df21132018-07-10 09:37:51 -0400158 if (type.columns() > 1) {
ethannicholasd598f792016-07-25 10:08:54 -0700159 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700160 }
John Stiles123501f2020-12-09 10:08:13 -0500161 return type.isFloat();
ethannicholasb3058bd2016-07-01 08:22:01 -0700162}
163
ethannicholasd598f792016-07-25 10:08:54 -0700164static bool is_signed(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500165 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700166 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700167 }
John Stiles123501f2020-12-09 10:08:13 -0500168 return type.isSigned();
ethannicholasb3058bd2016-07-01 08:22:01 -0700169}
170
ethannicholasd598f792016-07-25 10:08:54 -0700171static bool is_unsigned(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500172 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700173 return is_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700174 }
John Stiles123501f2020-12-09 10:08:13 -0500175 return type.isUnsigned();
ethannicholasb3058bd2016-07-01 08:22:01 -0700176}
177
ethannicholasd598f792016-07-25 10:08:54 -0700178static bool is_bool(const Context& context, const Type& type) {
John Stiles9aeed132020-11-24 17:36:06 -0500179 if (type.isVector()) {
ethannicholasd598f792016-07-25 10:08:54 -0700180 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700181 }
John Stiles123501f2020-12-09 10:08:13 -0500182 return type.isBoolean();
ethannicholasb3058bd2016-07-01 08:22:01 -0700183}
184
ethannicholasd598f792016-07-25 10:08:54 -0700185static bool is_out(const Variable& var) {
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400186 return (var.modifiers().fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700187}
188
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400189void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400190 SkASSERT(opCode != SpvOpLoad || &out != &fConstantBuffer);
191 SkASSERT(opCode != SpvOpUndef);
ethannicholasb3058bd2016-07-01 08:22:01 -0700192 switch (opCode) {
193 case SpvOpReturn: // fall through
194 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700195 case SpvOpKill: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700196 case SpvOpBranch: // fall through
197 case SpvOpBranchConditional:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400198 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700199 fCurrentBlock = 0;
200 break;
201 case SpvOpConstant: // fall through
202 case SpvOpConstantTrue: // fall through
203 case SpvOpConstantFalse: // fall through
204 case SpvOpConstantComposite: // fall through
205 case SpvOpTypeVoid: // fall through
206 case SpvOpTypeInt: // fall through
207 case SpvOpTypeFloat: // fall through
208 case SpvOpTypeBool: // fall through
209 case SpvOpTypeVector: // fall through
210 case SpvOpTypeMatrix: // fall through
211 case SpvOpTypeArray: // fall through
212 case SpvOpTypePointer: // fall through
213 case SpvOpTypeFunction: // fall through
214 case SpvOpTypeRuntimeArray: // fall through
215 case SpvOpTypeStruct: // fall through
216 case SpvOpTypeImage: // fall through
217 case SpvOpTypeSampledImage: // fall through
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400218 case SpvOpTypeSampler: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700219 case SpvOpVariable: // fall through
220 case SpvOpFunction: // fall through
221 case SpvOpFunctionParameter: // fall through
222 case SpvOpFunctionEnd: // fall through
223 case SpvOpExecutionMode: // fall through
224 case SpvOpMemoryModel: // fall through
225 case SpvOpCapability: // fall through
226 case SpvOpExtInstImport: // fall through
227 case SpvOpEntryPoint: // fall through
228 case SpvOpSource: // fall through
229 case SpvOpSourceExtension: // fall through
230 case SpvOpName: // fall through
231 case SpvOpMemberName: // fall through
232 case SpvOpDecorate: // fall through
233 case SpvOpMemberDecorate:
234 break;
235 default:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400236 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700237 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700238 this->writeWord((length << 16) | opCode, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700239}
240
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400241void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700242 fCurrentBlock = label;
243 this->writeInstruction(SpvOpLabel, label, out);
244}
245
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400246void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700247 this->writeOpCode(opCode, 1, out);
248}
249
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400250void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700251 this->writeOpCode(opCode, 2, out);
252 this->writeWord(word1, out);
253}
254
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700255void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputStream& out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400256 out.write(string, length);
ethannicholasb3058bd2016-07-01 08:22:01 -0700257 switch (length % 4) {
258 case 1:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500259 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400260 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700261 case 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500262 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400263 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700264 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500265 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700266 break;
267 default:
268 this->writeWord(0, out);
269 }
270}
271
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700272void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out) {
273 this->writeOpCode(opCode, 1 + (string.fLength + 4) / 4, out);
274 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700275}
276
277
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700278void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400279 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700280 this->writeOpCode(opCode, 2 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700281 this->writeWord(word1, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700282 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700283}
284
Greg Daniel64773e62016-11-22 09:44:03 -0500285void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700286 StringFragment string, OutputStream& out) {
287 this->writeOpCode(opCode, 3 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700288 this->writeWord(word1, out);
289 this->writeWord(word2, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700290 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700291}
292
Greg Daniel64773e62016-11-22 09:44:03 -0500293void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400294 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700295 this->writeOpCode(opCode, 3, out);
296 this->writeWord(word1, out);
297 this->writeWord(word2, out);
298}
299
Greg Daniel64773e62016-11-22 09:44:03 -0500300void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400301 int32_t word3, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700302 this->writeOpCode(opCode, 4, out);
303 this->writeWord(word1, out);
304 this->writeWord(word2, out);
305 this->writeWord(word3, out);
306}
307
Greg Daniel64773e62016-11-22 09:44:03 -0500308void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400309 int32_t word3, int32_t word4, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700310 this->writeOpCode(opCode, 5, out);
311 this->writeWord(word1, out);
312 this->writeWord(word2, out);
313 this->writeWord(word3, out);
314 this->writeWord(word4, out);
315}
316
Greg Daniel64773e62016-11-22 09:44:03 -0500317void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
318 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400319 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700320 this->writeOpCode(opCode, 6, out);
321 this->writeWord(word1, out);
322 this->writeWord(word2, out);
323 this->writeWord(word3, out);
324 this->writeWord(word4, out);
325 this->writeWord(word5, out);
326}
327
Greg Daniel64773e62016-11-22 09:44:03 -0500328void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700329 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400330 int32_t word6, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700331 this->writeOpCode(opCode, 7, out);
332 this->writeWord(word1, out);
333 this->writeWord(word2, out);
334 this->writeWord(word3, out);
335 this->writeWord(word4, out);
336 this->writeWord(word5, out);
337 this->writeWord(word6, 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, int32_t word7, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700343 this->writeOpCode(opCode, 8, 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 this->writeWord(word7, out);
351}
352
Greg Daniel64773e62016-11-22 09:44:03 -0500353void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700354 int32_t word3, int32_t word4, int32_t word5,
355 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400356 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700357 this->writeOpCode(opCode, 9, out);
358 this->writeWord(word1, out);
359 this->writeWord(word2, out);
360 this->writeWord(word3, out);
361 this->writeWord(word4, out);
362 this->writeWord(word5, out);
363 this->writeWord(word6, out);
364 this->writeWord(word7, out);
365 this->writeWord(word8, out);
366}
367
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400368void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700369 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
370 if (fCapabilities & bit) {
371 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
372 }
373 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400374 if (fProgram.fKind == Program::kGeometry_Kind) {
375 this->writeInstruction(SpvOpCapability, SpvCapabilityGeometry, out);
376 }
Ethan Nicholas81d15112018-07-13 12:48:50 -0400377 else {
378 this->writeInstruction(SpvOpCapability, SpvCapabilityShader, out);
379 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700380}
381
382SpvId SPIRVCodeGenerator::nextId() {
383 return fIdCount++;
384}
385
Ethan Nicholas19671772016-11-28 16:30:17 -0500386void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
387 SpvId resultId) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400388 this->writeInstruction(SpvOpName, resultId, String(type.name()).c_str(), fNameBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700389 // go ahead and write all of the field types, so we don't inadvertently write them while we're
390 // in the middle of writing the struct instruction
391 std::vector<SpvId> types;
392 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500393 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700394 }
395 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
396 this->writeWord(resultId, fConstantBuffer);
397 for (SpvId id : types) {
398 this->writeWord(id, fConstantBuffer);
399 }
400 size_t offset = 0;
401 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400402 const Type::Field& field = type.fields()[i];
John Stiles21f5f452020-11-30 09:57:59 -0500403 if (!MemoryLayout::LayoutIsSupported(*field.fType)) {
John Stiles0023c0c2020-11-16 13:32:18 -0500404 fErrors.error(type.fOffset, "type '" + field.fType->name() + "' is not permitted here");
405 return;
406 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400407 size_t size = memoryLayout.size(*field.fType);
408 size_t alignment = memoryLayout.alignment(*field.fType);
409 const Layout& fieldLayout = field.fModifiers.fLayout;
Ethan Nicholas19671772016-11-28 16:30:17 -0500410 if (fieldLayout.fOffset >= 0) {
Greg Danieldbd44c72017-01-24 15:12:12 -0500411 if (fieldLayout.fOffset < (int) offset) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700412 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400413 "offset of field '" + field.fName + "' must be at "
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500414 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -0500415 }
416 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700417 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400418 "offset of field '" + field.fName + "' must be a multiple"
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500419 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -0500420 }
421 offset = fieldLayout.fOffset;
422 } else {
423 size_t mod = offset % alignment;
424 if (mod) {
425 offset += alignment - mod;
426 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700427 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400428 this->writeInstruction(SpvOpMemberName, resultId, i, field.fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500429 this->writeLayout(fieldLayout, resultId, i);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400430 if (field.fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -0500431 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700432 (SpvId) offset, fDecorationBuffer);
433 }
John Stiles9aeed132020-11-24 17:36:06 -0500434 if (field.fType->isMatrix()) {
Greg Daniel64773e62016-11-22 09:44:03 -0500435 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -0700436 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500437 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400438 (SpvId) memoryLayout.stride(*field.fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800439 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700440 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400441 if (!field.fType->highPrecision()) {
442 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i,
443 SpvDecorationRelaxedPrecision, fDecorationBuffer);
444 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700445 offset += size;
John Stilesc0c51062020-12-03 17:16:29 -0500446 if ((field.fType->isArray() || field.fType->isStruct()) && offset % alignment != 0) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700447 offset += alignment - offset % alignment;
448 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700449 }
450}
451
Ethan Nicholase2c49992020-10-05 11:49:11 -0400452const Type& SPIRVCodeGenerator::getActualType(const Type& type) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500453 if (type.isFloat()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400454 return *fContext.fFloat_Type;
455 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500456 if (type.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400457 return *fContext.fInt_Type;
458 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500459 if (type.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400460 return *fContext.fUInt_Type;
461 }
John Stiles9aeed132020-11-24 17:36:06 -0500462 if (type.isMatrix() || type.isVector()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400463 if (type.componentType() == *fContext.fHalf_Type) {
464 return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
465 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400466 if (type.componentType() == *fContext.fShort_Type ||
467 type.componentType() == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400468 return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
469 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400470 if (type.componentType() == *fContext.fUShort_Type ||
471 type.componentType() == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400472 return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
473 }
474 }
475 return type;
476}
477
ethannicholasb3058bd2016-07-01 08:22:01 -0700478SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800479 return this->getType(type, fDefaultLayout);
480}
481
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400482SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400483 const Type& type = this->getActualType(rawType);
Jim Van Verthf3ec9832020-10-21 16:09:57 -0400484 String key = type.name();
John Stilesc0c51062020-12-03 17:16:29 -0500485 if (type.isStruct() || type.isArray()) {
Jim Van Verthf3ec9832020-10-21 16:09:57 -0400486 key += to_string((int)layout.fStd);
487 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800488 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700489 if (entry == fTypeMap.end()) {
490 SpvId result = this->nextId();
Ethan Nicholase6592142020-09-08 10:22:09 -0400491 switch (type.typeKind()) {
492 case Type::TypeKind::kScalar:
John Stiles4a7dc462020-11-25 11:08:08 -0500493 if (type.isBoolean()) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700494 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500495 } else if (type == *fContext.fInt_Type || type == *fContext.fShort_Type ||
496 type == *fContext.fIntLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700497 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500498 } else if (type == *fContext.fUInt_Type || type == *fContext.fUShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700499 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500500 } else if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type ||
501 type == *fContext.fFloatLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700502 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700503 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400504 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700505 }
506 break;
John Stilesfd41d872020-11-25 22:39:45 -0500507 case Type::TypeKind::kEnum:
508 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
509 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400510 case Type::TypeKind::kVector:
Greg Daniel64773e62016-11-22 09:44:03 -0500511 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800512 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700513 type.columns(), fConstantBuffer);
514 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400515 case Type::TypeKind::kMatrix:
Greg Daniel64773e62016-11-22 09:44:03 -0500516 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800517 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700518 type.columns(), fConstantBuffer);
519 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400520 case Type::TypeKind::kStruct:
ethannicholas8ac838d2016-11-22 08:39:36 -0800521 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700522 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400523 case Type::TypeKind::kArray: {
John Stiles21f5f452020-11-30 09:57:59 -0500524 if (!MemoryLayout::LayoutIsSupported(type)) {
525 fErrors.error(type.fOffset, "type '" + type.name() + "' is not permitted here");
526 return this->nextId();
527 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700528 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700529 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500530 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800531 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700532 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500533 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400534 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800535 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700536 } else {
John Stiles5570c512020-11-19 17:58:07 -0500537 // We shouldn't have any runtime-sized arrays right now
538 fErrors.error(type.fOffset, "runtime-sized arrays are not supported in SPIR-V");
Greg Daniel64773e62016-11-22 09:44:03 -0500539 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800540 this->getType(type.componentType(), layout),
541 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400542 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
543 (int32_t) layout.stride(type),
544 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700545 }
546 break;
547 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400548 case Type::TypeKind::kSampler: {
Greg Daniel64773e62016-11-22 09:44:03 -0500549 SpvId image = result;
550 if (SpvDimSubpassData != type.dimensions()) {
Stephen White792e2302019-08-09 13:33:51 -0400551 image = this->getType(type.textureType(), layout);
Greg Daniel64773e62016-11-22 09:44:03 -0500552 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400553 if (SpvDimBuffer == type.dimensions()) {
554 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
555 }
Greg Daniel64773e62016-11-22 09:44:03 -0500556 if (SpvDimSubpassData != type.dimensions()) {
557 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
558 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700559 break;
560 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400561 case Type::TypeKind::kSeparateSampler: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400562 this->writeInstruction(SpvOpTypeSampler, result, fConstantBuffer);
563 break;
564 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400565 case Type::TypeKind::kTexture: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400566 this->writeInstruction(SpvOpTypeImage, result,
567 this->getType(*fContext.fFloat_Type, layout),
John Stilesc0c51062020-12-03 17:16:29 -0500568 type.dimensions(), type.isDepth(), type.isArrayedTexture(),
Stephen White792e2302019-08-09 13:33:51 -0400569 type.isMultisampled(), type.isSampled() ? 1 : 2,
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400570 SpvImageFormatUnknown, fConstantBuffer);
571 fImageTypeMap[key] = result;
572 break;
573 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700574 default:
ethannicholasd598f792016-07-25 10:08:54 -0700575 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700576 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
577 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500578#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700579 ABORT("invalid type: %s", type.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500580#endif
ethannicholasb3058bd2016-07-01 08:22:01 -0700581 }
582 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800583 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700584 return result;
585 }
586 return entry->second;
587}
588
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400589SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400590 SkASSERT(type.typeKind() == Type::TypeKind::kSampler);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400591 this->getType(type);
592 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400593 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400594 return fImageTypeMap[key];
595}
596
ethannicholasd598f792016-07-25 10:08:54 -0700597SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400598 String key = to_string(this->getType(function.returnType())) + "(";
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400599 String separator;
Brian Osman5bf3e202020-10-13 10:34:18 -0400600 const std::vector<const Variable*>& parameters = function.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400601 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700602 key += separator;
603 separator = ", ";
Ethan Nicholased84b732020-10-08 11:45:44 -0400604 key += to_string(this->getType(parameters[i]->type()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700605 }
606 key += ")";
607 auto entry = fTypeMap.find(key);
608 if (entry == fTypeMap.end()) {
609 SpvId result = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -0400610 int32_t length = 3 + (int32_t) parameters.size();
611 SpvId returnType = this->getType(function.returnType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700612 std::vector<SpvId> parameterTypes;
Ethan Nicholased84b732020-10-08 11:45:44 -0400613 for (size_t i = 0; i < parameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500614 // glslang seems to treat all function arguments as pointers whether they need to be or
615 // not. I was initially puzzled by this until I ran bizarre failures with certain
616 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700617 // failure case:
618 //
619 // void sphere(float x) {
620 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500621 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700622 // void map() {
623 // sphere(1.0);
624 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500625 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700626 // void main() {
627 // for (int i = 0; i < 1; i++) {
628 // map();
629 // }
630 // }
631 //
Greg Daniel64773e62016-11-22 09:44:03 -0500632 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
633 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700634 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
635 // the spec makes this make sense.
636// if (is_out(function->fParameters[i])) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400637 parameterTypes.push_back(this->getPointerType(parameters[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -0700638 SpvStorageClassFunction));
639// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700640// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700641// }
642 }
643 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
644 this->writeWord(result, fConstantBuffer);
645 this->writeWord(returnType, fConstantBuffer);
646 for (SpvId id : parameterTypes) {
647 this->writeWord(id, fConstantBuffer);
648 }
649 fTypeMap[key] = result;
650 return result;
651 }
652 return entry->second;
653}
654
ethannicholas8ac838d2016-11-22 08:39:36 -0800655SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
656 return this->getPointerType(type, fDefaultLayout, storageClass);
657}
658
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400659SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700660 SpvStorageClass_ storageClass) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400661 const Type& type = this->getActualType(rawType);
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500662 String key = type.displayName() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700663 auto entry = fTypeMap.find(key);
664 if (entry == fTypeMap.end()) {
665 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500666 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700667 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700668 fTypeMap[key] = result;
669 return result;
670 }
671 return entry->second;
672}
673
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400674SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400675 switch (expr.kind()) {
676 case Expression::Kind::kBinary:
John Stiles81365af2020-08-18 09:24:00 -0400677 return this->writeBinaryExpression(expr.as<BinaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400678 case Expression::Kind::kBoolLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400679 return this->writeBoolLiteral(expr.as<BoolLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400680 case Expression::Kind::kConstructor:
John Stiles81365af2020-08-18 09:24:00 -0400681 return this->writeConstructor(expr.as<Constructor>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400682 case Expression::Kind::kIntLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400683 return this->writeIntLiteral(expr.as<IntLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400684 case Expression::Kind::kFieldAccess:
John Stiles81365af2020-08-18 09:24:00 -0400685 return this->writeFieldAccess(expr.as<FieldAccess>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400686 case Expression::Kind::kFloatLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400687 return this->writeFloatLiteral(expr.as<FloatLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400688 case Expression::Kind::kFunctionCall:
John Stiles81365af2020-08-18 09:24:00 -0400689 return this->writeFunctionCall(expr.as<FunctionCall>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400690 case Expression::Kind::kPrefix:
John Stiles81365af2020-08-18 09:24:00 -0400691 return this->writePrefixExpression(expr.as<PrefixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400692 case Expression::Kind::kPostfix:
John Stiles81365af2020-08-18 09:24:00 -0400693 return this->writePostfixExpression(expr.as<PostfixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400694 case Expression::Kind::kSwizzle:
John Stiles81365af2020-08-18 09:24:00 -0400695 return this->writeSwizzle(expr.as<Swizzle>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400696 case Expression::Kind::kVariableReference:
John Stiles81365af2020-08-18 09:24:00 -0400697 return this->writeVariableReference(expr.as<VariableReference>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400698 case Expression::Kind::kTernary:
John Stiles81365af2020-08-18 09:24:00 -0400699 return this->writeTernaryExpression(expr.as<TernaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400700 case Expression::Kind::kIndex:
John Stiles81365af2020-08-18 09:24:00 -0400701 return this->writeIndexExpression(expr.as<IndexExpression>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700702 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500703#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700704 ABORT("unsupported expression: %s", expr.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500705#endif
706 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700707 }
708 return -1;
709}
710
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400711SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400712 const FunctionDeclaration& function = c.function();
John Stiles8e3b6be2020-10-13 11:14:08 -0400713 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400714 auto intrinsic = fIntrinsicMap.find(function.name());
John Stiles93e661a2020-12-08 16:17:00 -0500715 if (intrinsic == fIntrinsicMap.end()) {
716 fErrors.error(c.fOffset, "unsupported intrinsic '" + function.description() + "'");
717 return -1;
718 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700719 int32_t intrinsicId;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400720 if (arguments.size() > 0) {
721 const Type& type = arguments[0]->type();
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400722 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
723 intrinsicId = std::get<1>(intrinsic->second);
724 } else if (is_signed(fContext, type)) {
725 intrinsicId = std::get<2>(intrinsic->second);
726 } else if (is_unsigned(fContext, type)) {
727 intrinsicId = std::get<3>(intrinsic->second);
728 } else if (is_bool(fContext, type)) {
729 intrinsicId = std::get<4>(intrinsic->second);
730 } else {
731 intrinsicId = std::get<1>(intrinsic->second);
732 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700733 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400734 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700735 }
736 switch (std::get<0>(intrinsic->second)) {
737 case kGLSL_STD_450_IntrinsicKind: {
738 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400739 std::vector<SpvId> argumentIds;
740 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400741 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400742 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400743 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400744 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400745 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700746 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400747 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400748 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700749 this->writeWord(result, out);
750 this->writeWord(fGLSLExtendedInstructions, out);
751 this->writeWord(intrinsicId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400752 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700753 this->writeWord(id, out);
754 }
755 return result;
756 }
757 case kSPIRV_IntrinsicKind: {
Brian Osman46787d52020-11-24 14:18:23 -0500758 // GLSL supports dot(float, float), but SPIR-V does not. Convert it to FMul
John Stiles9aeed132020-11-24 17:36:06 -0500759 if (intrinsicId == SpvOpDot && arguments[0]->type().isScalar()) {
Brian Osman46787d52020-11-24 14:18:23 -0500760 intrinsicId = SpvOpFMul;
761 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700762 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400763 std::vector<SpvId> argumentIds;
764 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400765 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400766 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400767 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400768 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400769 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700770 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400771 if (c.type() != *fContext.fVoid_Type) {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400772 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400773 this->writeWord(this->getType(c.type()), out);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400774 this->writeWord(result, out);
775 } else {
776 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
777 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400778 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700779 this->writeWord(id, out);
780 }
781 return result;
782 }
783 case kSpecial_IntrinsicKind:
784 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
785 default:
John Stiles93e661a2020-12-08 16:17:00 -0500786 fErrors.error(c.fOffset, "unsupported intrinsic '" + function.description() + "'");
787 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -0700788 }
789}
790
John Stiles8e3b6be2020-10-13 11:14:08 -0400791std::vector<SpvId> SPIRVCodeGenerator::vectorize(const ExpressionArray& args, OutputStream& out) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500792 int vectorSize = 0;
793 for (const auto& a : args) {
John Stiles9aeed132020-11-24 17:36:06 -0500794 if (a->type().isVector()) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500795 if (vectorSize) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400796 SkASSERT(a->type().columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500797 }
798 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400799 vectorSize = a->type().columns();
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500800 }
801 }
802 }
803 std::vector<SpvId> result;
John Stiles8e3b6be2020-10-13 11:14:08 -0400804 result.reserve(args.size());
Ethan Nicholas30d30222020-09-11 12:27:26 -0400805 for (const auto& arg : args) {
806 const Type& argType = arg->type();
807 SpvId raw = this->writeExpression(*arg, out);
John Stiles9aeed132020-11-24 17:36:06 -0500808 if (vectorSize && argType.isScalar()) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500809 SpvId vector = this->nextId();
810 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400811 this->writeWord(this->getType(argType.toCompound(fContext, vectorSize, 1)), out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500812 this->writeWord(vector, out);
813 for (int i = 0; i < vectorSize; i++) {
814 this->writeWord(raw, out);
815 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400816 this->writePrecisionModifier(argType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500817 result.push_back(vector);
818 } else {
819 result.push_back(raw);
820 }
821 }
822 return result;
823}
824
825void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
826 SpvId signedInst, SpvId unsignedInst,
827 const std::vector<SpvId>& args,
828 OutputStream& out) {
829 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
830 this->writeWord(this->getType(type), out);
831 this->writeWord(id, out);
832 this->writeWord(fGLSLExtendedInstructions, out);
833
834 if (is_float(fContext, type)) {
835 this->writeWord(floatInst, out);
836 } else if (is_signed(fContext, type)) {
837 this->writeWord(signedInst, out);
838 } else if (is_unsigned(fContext, type)) {
839 this->writeWord(unsignedInst, out);
840 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400841 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500842 }
843 for (SpvId a : args) {
844 this->writeWord(a, out);
845 }
846}
847
Greg Daniel64773e62016-11-22 09:44:03 -0500848SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400849 OutputStream& out) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400850 const ExpressionArray& arguments = c.arguments();
ethannicholasb3058bd2016-07-01 08:22:01 -0700851 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400852 const Type& callType = c.type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700853 switch (kind) {
854 case kAtan_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400855 std::vector<SpvId> argumentIds;
856 for (const std::unique_ptr<Expression>& arg : arguments) {
857 argumentIds.push_back(this->writeExpression(*arg, out));
ethannicholasb3058bd2016-07-01 08:22:01 -0700858 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400859 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400860 this->writeWord(this->getType(callType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700861 this->writeWord(result, out);
862 this->writeWord(fGLSLExtendedInstructions, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400863 this->writeWord(argumentIds.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
864 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700865 this->writeWord(id, out);
866 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400867 break;
868 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400869 case kSampledImage_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400870 SkASSERT(arguments.size() == 2);
871 SpvId img = this->writeExpression(*arguments[0], out);
872 SpvId sampler = this->writeExpression(*arguments[1], out);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400873 this->writeInstruction(SpvOpSampledImage,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400874 this->getType(callType),
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400875 result,
876 img,
877 sampler,
878 out);
879 break;
880 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400881 case kSubpassLoad_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400882 SpvId img = this->writeExpression(*arguments[0], out);
John Stiles8e3b6be2020-10-13 11:14:08 -0400883 ExpressionArray args;
John Stilesf4bda742020-10-14 16:57:41 -0400884 args.reserve_back(2);
John Stiles8e3b6be2020-10-13 11:14:08 -0400885 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
886 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
Ethan Nicholas30d30222020-09-11 12:27:26 -0400887 Constructor ctor(-1, fContext.fInt2_Type.get(), std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400888 SpvId coords = this->writeConstantVector(ctor);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400889 if (arguments.size() == 1) {
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400890 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400891 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400892 result,
893 img,
894 coords,
895 out);
896 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400897 SkASSERT(arguments.size() == 2);
898 SpvId sample = this->writeExpression(*arguments[1], out);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400899 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400900 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400901 result,
902 img,
903 coords,
904 SpvImageOperandsSampleMask,
905 sample,
906 out);
907 }
908 break;
909 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700910 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500911 SpvOp_ op = SpvOpImageSampleImplicitLod;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400912 const Type& arg1Type = arguments[1]->type();
913 switch (arguments[0]->type().dimensions()) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500914 case SpvDim1D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400915 if (arg1Type == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500916 op = SpvOpImageSampleProjImplicitLod;
917 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400918 SkASSERT(arg1Type == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500919 }
920 break;
921 case SpvDim2D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400922 if (arg1Type == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500923 op = SpvOpImageSampleProjImplicitLod;
924 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400925 SkASSERT(arg1Type == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500926 }
927 break;
928 case SpvDim3D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400929 if (arg1Type == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500930 op = SpvOpImageSampleProjImplicitLod;
931 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400932 SkASSERT(arg1Type == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500933 }
934 break;
935 case SpvDimCube: // fall through
936 case SpvDimRect: // fall through
937 case SpvDimBuffer: // fall through
938 case SpvDimSubpassData:
939 break;
940 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400941 SpvId type = this->getType(callType);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400942 SpvId sampler = this->writeExpression(*arguments[0], out);
943 SpvId uv = this->writeExpression(*arguments[1], out);
944 if (arguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500945 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700946 SpvImageOperandsBiasMask,
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400947 this->writeExpression(*arguments[2], out),
ethannicholasb3058bd2016-07-01 08:22:01 -0700948 out);
949 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400950 SkASSERT(arguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500951 if (fProgram.fSettings.fSharpenTextures) {
952 FloatLiteral lodBias(fContext, -1, -0.5);
953 this->writeInstruction(op, type, result, sampler, uv,
954 SpvImageOperandsBiasMask,
955 this->writeFloatLiteral(lodBias),
956 out);
957 } else {
958 this->writeInstruction(op, type, result, sampler, uv,
959 out);
960 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700961 }
962 break;
963 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500964 case kMod_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400965 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400966 SkASSERT(args.size() == 2);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400967 const Type& operandType = arguments[0]->type();
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500968 SpvOp_ op;
969 if (is_float(fContext, operandType)) {
970 op = SpvOpFMod;
971 } else if (is_signed(fContext, operandType)) {
972 op = SpvOpSMod;
973 } else if (is_unsigned(fContext, operandType)) {
974 op = SpvOpUMod;
975 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400976 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500977 return 0;
978 }
979 this->writeOpCode(op, 5, out);
980 this->writeWord(this->getType(operandType), out);
981 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500982 this->writeWord(args[0], out);
983 this->writeWord(args[1], out);
984 break;
985 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700986 case kDFdy_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400987 SpvId fn = this->writeExpression(*arguments[0], out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700988 this->writeOpCode(SpvOpDPdy, 4, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400989 this->writeWord(this->getType(callType), out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700990 this->writeWord(result, out);
991 this->writeWord(fn, out);
992 if (fProgram.fSettings.fFlipY) {
993 // Flipping Y also negates the Y derivatives.
994 SpvId flipped = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400995 this->writeInstruction(SpvOpFNegate, this->getType(callType), flipped, result,
996 out);
997 this->writePrecisionModifier(callType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700998 return flipped;
999 }
1000 break;
1001 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001002 case kClamp_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001003 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001004 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001005 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001006 GLSLstd450UClamp, args, out);
1007 break;
1008 }
1009 case kMax_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001010 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001011 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001012 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMax, GLSLstd450SMax,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001013 GLSLstd450UMax, args, out);
1014 break;
1015 }
1016 case kMin_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001017 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001018 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001019 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMin, GLSLstd450SMin,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001020 GLSLstd450UMin, args, out);
1021 break;
1022 }
1023 case kMix_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001024 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001025 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001026 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMix, SpvOpUndef,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001027 SpvOpUndef, args, out);
1028 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -05001029 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001030 case kSaturate_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001031 SkASSERT(arguments.size() == 1);
John Stiles8e3b6be2020-10-13 11:14:08 -04001032 ExpressionArray finalArgs;
John Stilesf4bda742020-10-14 16:57:41 -04001033 finalArgs.reserve_back(3);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001034 finalArgs.push_back(arguments[0]->clone());
John Stiles8e3b6be2020-10-13 11:14:08 -04001035 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1036 /*value=*/0));
1037 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1038 /*value=*/1));
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001039 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001040 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001041 GLSLstd450UClamp, spvArgs, out);
1042 break;
1043 }
Brian Osman6ba3be12020-11-13 16:32:52 -05001044 case kSmoothStep_SpecialIntrinsic: {
1045 std::vector<SpvId> args = this->vectorize(arguments, out);
1046 SkASSERT(args.size() == 3);
1047 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450SmoothStep, SpvOpUndef,
1048 SpvOpUndef, args, out);
1049 break;
1050 }
1051 case kStep_SpecialIntrinsic: {
1052 std::vector<SpvId> args = this->vectorize(arguments, out);
1053 SkASSERT(args.size() == 2);
1054 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450Step, SpvOpUndef,
1055 SpvOpUndef, args, out);
1056 break;
1057 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001058 }
1059 return result;
1060}
1061
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001062SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001063 const FunctionDeclaration& function = c.function();
John Stiles8e3b6be2020-10-13 11:14:08 -04001064 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001065 const auto& entry = fFunctionMap.find(&function);
ethannicholasb3058bd2016-07-01 08:22:01 -07001066 if (entry == fFunctionMap.end()) {
1067 return this->writeIntrinsicCall(c, out);
1068 }
1069 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001070 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001071 std::vector<SpvId> argumentIds;
1072 for (size_t i = 0; i < arguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001073 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001074 // passed directly
1075 SpvId tmpVar;
1076 // if we need a temporary var to store this argument, this is the value to store in the var
1077 SpvId tmpValueId;
Ethan Nicholased84b732020-10-08 11:45:44 -04001078 if (is_out(*function.parameters()[i])) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001079 std::unique_ptr<LValue> lv = this->getLValue(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001080 SpvId ptr = lv->getPointer();
1081 if (ptr) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001082 argumentIds.push_back(ptr);
ethannicholasb3058bd2016-07-01 08:22:01 -07001083 continue;
1084 } else {
1085 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1086 // copy it into a temp, call the function, read the value out of the temp, and then
1087 // update the lvalue.
1088 tmpValueId = lv->load(out);
1089 tmpVar = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001090 lvalues.push_back(std::make_tuple(tmpVar, &arguments[i]->type(), std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001091 }
1092 } else {
1093 // see getFunctionType for an explanation of why we're always using pointer parameters
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001094 tmpValueId = this->writeExpression(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001095 tmpVar = this->nextId();
1096 }
Greg Daniel64773e62016-11-22 09:44:03 -05001097 this->writeInstruction(SpvOpVariable,
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001098 this->getPointerType(arguments[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001099 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001100 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001101 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001102 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001103 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001104 argumentIds.push_back(tmpVar);
ethannicholasb3058bd2016-07-01 08:22:01 -07001105 }
1106 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001107 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001108 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001109 this->writeWord(result, out);
1110 this->writeWord(entry->second, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001111 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001112 this->writeWord(id, out);
1113 }
1114 // now that the call is complete, we may need to update some lvalues with the new values of out
1115 // arguments
1116 for (const auto& tuple : lvalues) {
1117 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001118 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1119 out);
1120 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001121 std::get<2>(tuple)->store(load, out);
1122 }
1123 return result;
1124}
1125
ethannicholasf789b382016-08-03 12:43:36 -07001126SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001127 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001128 SkASSERT(type.isVector() && c.isCompileTimeConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001129 SpvId result = this->nextId();
1130 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001131 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1132 arguments.push_back(this->writeExpression(*arg, fConstantBuffer));
ethannicholasb3058bd2016-07-01 08:22:01 -07001133 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001134 SpvId typeId = this->getType(type);
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001135 if (c.arguments().size() == 1) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001136 // with a single argument, a vector will have all of its entries equal to the argument
Ethan Nicholas30d30222020-09-11 12:27:26 -04001137 this->writeOpCode(SpvOpConstantComposite, 3 + type.columns(), fConstantBuffer);
1138 this->writeWord(typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001139 this->writeWord(result, fConstantBuffer);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001140 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001141 this->writeWord(arguments[0], fConstantBuffer);
1142 }
1143 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001144 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.arguments().size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001145 fConstantBuffer);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001146 this->writeWord(typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001147 this->writeWord(result, fConstantBuffer);
1148 for (SpvId id : arguments) {
1149 this->writeWord(id, fConstantBuffer);
1150 }
1151 }
1152 return result;
1153}
1154
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001155SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001156 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001157 SkASSERT(c.arguments().size() == 1);
1158 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001159 SkASSERT(constructorType.isFloat());
1160 SkASSERT(argType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001161 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001162 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001163 if (argType.isSigned()) {
1164 this->writeInstruction(SpvOpConvertSToF, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001165 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001166 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001167 SkASSERT(argType.isUnsigned());
1168 this->writeInstruction(SpvOpConvertUToF, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001169 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001170 }
1171 return result;
1172}
1173
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001174SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001175 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001176 SkASSERT(c.arguments().size() == 1);
1177 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001178 SkASSERT(constructorType.isSigned());
1179 SkASSERT(argType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001180 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001181 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001182 if (argType.isFloat()) {
1183 this->writeInstruction(SpvOpConvertFToS, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001184 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001185 }
1186 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001187 SkASSERT(argType.isUnsigned());
1188 this->writeInstruction(SpvOpBitcast, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001189 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001190 }
1191 return result;
1192}
1193
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001194SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001195 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001196 SkASSERT(c.arguments().size() == 1);
1197 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001198 SkASSERT(constructorType.isUnsigned());
1199 SkASSERT(argType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001200 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001201 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001202 if (argType.isFloat()) {
1203 this->writeInstruction(SpvOpConvertFToU, this->getType(constructorType), result, parameter,
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001204 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001205 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001206 SkASSERT(argType.isSigned());
1207 this->writeInstruction(SpvOpBitcast, this->getType(constructorType), result, parameter,
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001208 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001209 }
1210 return result;
1211}
1212
Ethan Nicholas84645e32017-02-09 13:57:14 -05001213void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001214 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001215 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001216 SpvId zeroId = this->writeFloatLiteral(zero);
1217 std::vector<SpvId> columnIds;
1218 for (int column = 0; column < type.columns(); column++) {
1219 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1220 out);
1221 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1222 out);
1223 SpvId columnId = this->nextId();
1224 this->writeWord(columnId, out);
1225 columnIds.push_back(columnId);
1226 for (int row = 0; row < type.columns(); row++) {
1227 this->writeWord(row == column ? diagonal : zeroId, out);
1228 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001229 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001230 }
1231 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1232 out);
1233 this->writeWord(this->getType(type), out);
1234 this->writeWord(id, out);
John Stilesf621e232020-08-25 13:33:02 -04001235 for (SpvId columnId : columnIds) {
1236 this->writeWord(columnId, out);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001237 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001238 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001239}
1240
1241void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001242 const Type& dstType, OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05001243 SkASSERT(srcType.isMatrix());
1244 SkASSERT(dstType.isMatrix());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001245 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001246 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1247 srcType.rows(),
1248 1));
1249 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1250 dstType.rows(),
1251 1));
1252 SpvId zeroId;
1253 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001254 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001255 zeroId = this->writeFloatLiteral(zero);
1256 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001257 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001258 zeroId = this->writeIntLiteral(zero);
1259 } else {
1260 ABORT("unsupported matrix component type");
1261 }
1262 SpvId zeroColumn = 0;
1263 SpvId columns[4];
1264 for (int i = 0; i < dstType.columns(); i++) {
1265 if (i < srcType.columns()) {
1266 // we're still inside the src matrix, copy the column
1267 SpvId srcColumn = this->nextId();
1268 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001269 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001270 SpvId dstColumn;
1271 if (srcType.rows() == dstType.rows()) {
1272 // columns are equal size, don't need to do anything
1273 dstColumn = srcColumn;
1274 }
1275 else if (dstType.rows() > srcType.rows()) {
1276 // dst column is bigger, need to zero-pad it
1277 dstColumn = this->nextId();
1278 int delta = dstType.rows() - srcType.rows();
1279 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1280 this->writeWord(dstColumnType, out);
1281 this->writeWord(dstColumn, out);
1282 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001283 for (int j = 0; j < delta; ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001284 this->writeWord(zeroId, out);
1285 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001286 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001287 }
1288 else {
1289 // dst column is smaller, need to swizzle the src column
1290 dstColumn = this->nextId();
1291 int count = dstType.rows();
1292 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1293 this->writeWord(dstColumnType, out);
1294 this->writeWord(dstColumn, out);
1295 this->writeWord(srcColumn, out);
1296 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001297 for (int j = 0; j < count; j++) {
1298 this->writeWord(j, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001299 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001300 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001301 }
1302 columns[i] = dstColumn;
1303 } else {
1304 // we're past the end of the src matrix, need a vector of zeroes
1305 if (!zeroColumn) {
1306 zeroColumn = this->nextId();
1307 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1308 this->writeWord(dstColumnType, out);
1309 this->writeWord(zeroColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001310 for (int j = 0; j < dstType.rows(); ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001311 this->writeWord(zeroId, out);
1312 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001313 this->writePrecisionModifier(dstType, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001314 }
1315 columns[i] = zeroColumn;
1316 }
1317 }
1318 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1319 this->writeWord(this->getType(dstType), out);
1320 this->writeWord(id, out);
1321 for (int i = 0; i < dstType.columns(); i++) {
1322 this->writeWord(columns[i], out);
1323 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001324 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001325}
1326
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001327void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1328 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001329 std::vector<SpvId>* columnIds,
1330 int* currentCount, int rows, SpvId entry,
1331 OutputStream& out) {
1332 SkASSERT(*currentCount < rows);
1333 ++(*currentCount);
1334 currentColumn->push_back(entry);
1335 if (*currentCount == rows) {
1336 *currentCount = 0;
1337 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1338 this->writeWord(columnType, out);
1339 SpvId columnId = this->nextId();
1340 this->writeWord(columnId, out);
1341 columnIds->push_back(columnId);
1342 for (SpvId id : *currentColumn) {
1343 this->writeWord(id, out);
1344 }
1345 currentColumn->clear();
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001346 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001347 }
1348}
1349
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001350SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001351 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001352 SkASSERT(type.isMatrix());
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001353 SkASSERT(c.arguments().size() > 0);
1354 const Type& arg0Type = c.arguments()[0]->type();
ethannicholasb3058bd2016-07-01 08:22:01 -07001355 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1356 // an instruction
1357 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001358 for (size_t i = 0; i < c.arguments().size(); i++) {
1359 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001360 }
1361 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001362 int rows = type.rows();
1363 int columns = type.columns();
John Stiles9aeed132020-11-24 17:36:06 -05001364 if (arguments.size() == 1 && arg0Type.isScalar()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001365 this->writeUniformScaleMatrix(result, arguments[0], type, out);
John Stiles9aeed132020-11-24 17:36:06 -05001366 } else if (arguments.size() == 1 && arg0Type.isMatrix()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001367 this->writeMatrixCopy(result, arguments[0], arg0Type, type, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001368 } else if (arguments.size() == 1 &&
John Stiles9aeed132020-11-24 17:36:06 -05001369 arg0Type.isVector()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001370 SkASSERT(type.rows() == 2 && type.columns() == 2);
1371 SkASSERT(arg0Type.columns() == 4);
1372 SpvId componentType = this->getType(type.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001373 SpvId v[4];
1374 for (int i = 0; i < 4; ++i) {
1375 v[i] = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001376 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i,
1377 out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001378 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001379 SpvId columnType = this->getType(type.componentType().toCompound(fContext, 2, 1));
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001380 SpvId column1 = this->nextId();
1381 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1382 SpvId column2 = this->nextId();
1383 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001384 this->writeInstruction(SpvOpCompositeConstruct, this->getType(type), result, column1,
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001385 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001386 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001387 SpvId columnType = this->getType(type.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001388 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001389 // ids of vectors and scalars we have written to the current column so far
1390 std::vector<SpvId> currentColumn;
1391 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001392 int currentCount = 0;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001393 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001394 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001395 const Type& argType = c.arguments()[i]->type();
John Stiles9aeed132020-11-24 17:36:06 -05001396 if (currentCount == 0 && argType.isVector() &&
Ethan Nicholas30d30222020-09-11 12:27:26 -04001397 argType.columns() == type.rows()) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001398 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001399 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001400 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001401 if (argType.columns() == 1) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001402 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1403 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001404 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001405 SpvId componentType = this->getType(argType.componentType());
1406 for (int j = 0; j < argType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001407 SpvId swizzle = this->nextId();
1408 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1409 arguments[i], j, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001410 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1411 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001412 }
1413 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001414 }
1415 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001416 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001417 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001418 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001419 this->writeWord(result, out);
1420 for (SpvId id : columnIds) {
1421 this->writeWord(id, out);
1422 }
1423 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001424 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001425 return result;
1426}
1427
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001428SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001429 const Type& type = c.type();
John Stiles9aeed132020-11-24 17:36:06 -05001430 SkASSERT(type.isVector());
Brian Osmanb6b95732020-06-30 11:44:27 -04001431 if (c.isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001432 return this->writeConstantVector(c);
1433 }
1434 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1435 // an instruction
1436 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001437 for (size_t i = 0; i < c.arguments().size(); i++) {
1438 const Type& argType = c.arguments()[i]->type();
John Stiles9aeed132020-11-24 17:36:06 -05001439 if (argType.isVector()) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001440 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1441 // extract the components and convert them in that case manually. On top of that,
1442 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1443 // doesn't handle vector arguments at all, so we always extract vector components and
1444 // pass them into OpCreateComposite individually.
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001445 SpvId vec = this->writeExpression(*c.arguments()[i], out);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001446 SpvOp_ op = SpvOpUndef;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001447 const Type& src = argType.componentType();
1448 const Type& dst = type.componentType();
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001449 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1450 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001451 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001452 return vec;
1453 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001454 } else if (src == *fContext.fInt_Type ||
1455 src == *fContext.fShort_Type ||
1456 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001457 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001458 } else if (src == *fContext.fUInt_Type ||
1459 src == *fContext.fUShort_Type ||
1460 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001461 op = SpvOpConvertUToF;
1462 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001463 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001464 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001465 } else if (dst == *fContext.fInt_Type ||
1466 dst == *fContext.fShort_Type ||
1467 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001468 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1469 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001470 } else if (src == *fContext.fInt_Type ||
1471 src == *fContext.fShort_Type ||
1472 src == *fContext.fByte_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001473 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001474 return vec;
1475 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001476 } else if (src == *fContext.fUInt_Type ||
1477 src == *fContext.fUShort_Type ||
1478 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001479 op = SpvOpBitcast;
1480 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001481 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001482 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001483 } else if (dst == *fContext.fUInt_Type ||
1484 dst == *fContext.fUShort_Type ||
1485 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001486 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1487 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001488 } else if (src == *fContext.fInt_Type ||
1489 src == *fContext.fShort_Type ||
1490 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001491 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001492 } else if (src == *fContext.fUInt_Type ||
1493 src == *fContext.fUShort_Type ||
1494 src == *fContext.fUByte_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001495 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001496 return vec;
1497 }
1498 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001499 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001500 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001501 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001502 for (int j = 0; j < argType.columns(); j++) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001503 SpvId swizzle = this->nextId();
1504 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1505 out);
1506 if (op != SpvOpUndef) {
1507 SpvId cast = this->nextId();
1508 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1509 arguments.push_back(cast);
1510 } else {
1511 arguments.push_back(swizzle);
1512 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001513 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001514 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001515 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001516 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001517 }
1518 SpvId result = this->nextId();
John Stiles9aeed132020-11-24 17:36:06 -05001519 if (arguments.size() == 1 && c.arguments()[0]->type().isScalar()) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001520 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(), out);
1521 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001522 this->writeWord(result, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001523 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001524 this->writeWord(arguments[0], out);
1525 }
1526 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001527 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001528 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001529 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001530 this->writeWord(result, out);
1531 for (SpvId id : arguments) {
1532 this->writeWord(id, out);
1533 }
1534 }
1535 return result;
1536}
1537
Ethan Nicholasbd553222017-07-18 15:54:59 -04001538SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001539 const Type& type = c.type();
John Stilesc0c51062020-12-03 17:16:29 -05001540 SkASSERT(type.isArray());
Ethan Nicholasbd553222017-07-18 15:54:59 -04001541 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1542 // an instruction
1543 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001544 for (size_t i = 0; i < c.arguments().size(); i++) {
1545 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholasbd553222017-07-18 15:54:59 -04001546 }
1547 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001548 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.arguments().size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001549 this->writeWord(this->getType(type), out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001550 this->writeWord(result, out);
1551 for (SpvId id : arguments) {
1552 this->writeWord(id, out);
1553 }
1554 return result;
1555}
1556
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001557SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001558 const Type& type = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001559 if (c.arguments().size() == 1 &&
1560 this->getActualType(type) == this->getActualType(c.arguments()[0]->type())) {
1561 return this->writeExpression(*c.arguments()[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001562 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001563 if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001564 return this->writeFloatConstructor(c, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001565 } else if (type == *fContext.fInt_Type ||
1566 type == *fContext.fShort_Type ||
1567 type == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001568 return this->writeIntConstructor(c, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001569 } else if (type == *fContext.fUInt_Type ||
1570 type == *fContext.fUShort_Type ||
1571 type == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001572 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001573 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001574 switch (type.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001575 case Type::TypeKind::kVector:
ethannicholasb3058bd2016-07-01 08:22:01 -07001576 return this->writeVectorConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001577 case Type::TypeKind::kMatrix:
ethannicholasb3058bd2016-07-01 08:22:01 -07001578 return this->writeMatrixConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001579 case Type::TypeKind::kArray:
Ethan Nicholasbd553222017-07-18 15:54:59 -04001580 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001581 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001582#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07001583 ABORT("unsupported constructor: %s", c.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001584#endif
1585 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001586 }
1587}
1588
1589SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1590 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001591 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001592 return SpvStorageClassInput;
1593 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001594 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001595 return SpvStorageClassOutput;
1596 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001597 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001598 return SpvStorageClassPushConstant;
1599 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001600 return SpvStorageClassUniform;
1601 } else {
1602 return SpvStorageClassFunction;
1603 }
1604}
1605
ethannicholasf789b382016-08-03 12:43:36 -07001606SpvStorageClass_ get_storage_class(const Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001607 switch (expr.kind()) {
1608 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -04001609 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001610 if (var.storage() != Variable::Storage::kGlobal) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001611 return SpvStorageClassFunction;
1612 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001613 SpvStorageClass_ result = get_storage_class(var.modifiers());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001614 if (result == SpvStorageClassFunction) {
1615 result = SpvStorageClassPrivate;
1616 }
1617 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001618 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001619 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001620 return get_storage_class(*expr.as<FieldAccess>().base());
Ethan Nicholase6592142020-09-08 10:22:09 -04001621 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001622 return get_storage_class(*expr.as<IndexExpression>().base());
ethannicholasb3058bd2016-07-01 08:22:01 -07001623 default:
1624 return SpvStorageClassFunction;
1625 }
1626}
1627
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001628std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001629 std::vector<SpvId> chain;
Ethan Nicholase6592142020-09-08 10:22:09 -04001630 switch (expr.kind()) {
1631 case Expression::Kind::kIndex: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001632 IndexExpression& indexExpr = (IndexExpression&) expr;
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001633 chain = this->getAccessChain(*indexExpr.base(), out);
1634 chain.push_back(this->writeExpression(*indexExpr.index(), out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001635 break;
1636 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001637 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001638 FieldAccess& fieldExpr = (FieldAccess&) expr;
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001639 chain = this->getAccessChain(*fieldExpr.base(), out);
1640 IntLiteral index(fContext, -1, fieldExpr.fieldIndex());
ethannicholasb3058bd2016-07-01 08:22:01 -07001641 chain.push_back(this->writeIntLiteral(index));
1642 break;
1643 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001644 default: {
1645 SpvId id = this->getLValue(expr, out)->getPointer();
1646 SkASSERT(id != 0);
1647 chain.push_back(id);
1648 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001649 }
1650 return chain;
1651}
1652
1653class PointerLValue : public SPIRVCodeGenerator::LValue {
1654public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001655 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1656 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001657 : fGen(gen)
1658 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001659 , fType(type)
1660 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001661
John Stiles1cf2c8d2020-08-13 22:58:04 -04001662 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001663 return fPointer;
1664 }
1665
John Stiles1cf2c8d2020-08-13 22:58:04 -04001666 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001667 SpvId result = fGen.nextId();
1668 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001669 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001670 return result;
1671 }
1672
John Stiles1cf2c8d2020-08-13 22:58:04 -04001673 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001674 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1675 }
1676
1677private:
1678 SPIRVCodeGenerator& fGen;
1679 const SpvId fPointer;
1680 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001681 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001682};
1683
1684class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1685public:
John Stiles750109b2020-10-30 13:45:46 -04001686 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const ComponentArray& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001687 const Type& baseType, const Type& swizzleType,
1688 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001689 : fGen(gen)
1690 , fVecPointer(vecPointer)
1691 , fComponents(components)
1692 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001693 , fSwizzleType(swizzleType)
1694 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001695
John Stiles1cf2c8d2020-08-13 22:58:04 -04001696 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001697 return 0;
1698 }
1699
John Stiles1cf2c8d2020-08-13 22:58:04 -04001700 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001701 SpvId base = fGen.nextId();
1702 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001703 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001704 SpvId result = fGen.nextId();
1705 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1706 fGen.writeWord(fGen.getType(fSwizzleType), out);
1707 fGen.writeWord(result, out);
1708 fGen.writeWord(base, out);
1709 fGen.writeWord(base, out);
1710 for (int component : fComponents) {
1711 fGen.writeWord(component, out);
1712 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001713 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001714 return result;
1715 }
1716
John Stiles1cf2c8d2020-08-13 22:58:04 -04001717 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001718 // use OpVectorShuffle to mix and match the vector components. We effectively create
1719 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001720 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001721 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001722 // float3L = ...;
1723 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001724 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001725 // 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 -07001726 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1727 // (3, 1, 4).
1728 SpvId base = fGen.nextId();
1729 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1730 SpvId shuffle = fGen.nextId();
1731 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1732 fGen.writeWord(fGen.getType(fBaseType), out);
1733 fGen.writeWord(shuffle, out);
1734 fGen.writeWord(base, out);
1735 fGen.writeWord(value, out);
1736 for (int i = 0; i < fBaseType.columns(); i++) {
1737 // current offset into the virtual vector, defaults to pulling the unmodified
1738 // value from the left side
1739 int offset = i;
1740 // check to see if we are writing this component
1741 for (size_t j = 0; j < fComponents.size(); j++) {
1742 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001743 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001744 // the correct component of the right side instead of preserving the
1745 // value from the left
1746 offset = (int) (j + fBaseType.columns());
1747 break;
1748 }
1749 }
1750 fGen.writeWord(offset, out);
1751 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001752 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001753 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1754 }
1755
1756private:
1757 SPIRVCodeGenerator& fGen;
1758 const SpvId fVecPointer;
John Stiles750109b2020-10-30 13:45:46 -04001759 const ComponentArray& fComponents;
ethannicholasb3058bd2016-07-01 08:22:01 -07001760 const Type& fBaseType;
1761 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001762 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001763};
1764
Greg Daniel64773e62016-11-22 09:44:03 -05001765std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001766 OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001767 const Type& type = expr.type();
1768 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
Ethan Nicholase6592142020-09-08 10:22:09 -04001769 switch (expr.kind()) {
1770 case Expression::Kind::kVariableReference: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001771 SpvId typeId;
Ethan Nicholas78686922020-10-08 06:46:27 -04001772 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001773 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001774 typeId = this->getType(Type("sk_in", Type::TypeKind::kArray,
1775 var.type().componentType(), fSkInCount));
Ethan Nicholas5226b772018-05-03 16:20:41 -04001776 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001777 typeId = this->getType(type);
Ethan Nicholas5226b772018-05-03 16:20:41 -04001778 }
ethannicholasd598f792016-07-25 10:08:54 -07001779 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001780 SkASSERT(entry != fVariableMap.end());
John Stiles5570c512020-11-19 17:58:07 -05001781 return std::make_unique<PointerLValue>(*this, entry->second, typeId, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001782 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001783 case Expression::Kind::kIndex: // fall through
1784 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001785 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1786 SpvId member = this->nextId();
1787 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001788 this->writeWord(this->getPointerType(type, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001789 this->writeWord(member, out);
1790 for (SpvId idx : chain) {
1791 this->writeWord(idx, out);
1792 }
John Stiles5570c512020-11-19 17:58:07 -05001793 return std::make_unique<PointerLValue>(*this, member, this->getType(type), precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001794 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001795 case Expression::Kind::kSwizzle: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001796 Swizzle& swizzle = (Swizzle&) expr;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001797 size_t count = swizzle.components().size();
1798 SpvId base = this->getLValue(*swizzle.base(), out)->getPointer();
John Stiles5570c512020-11-19 17:58:07 -05001799 if (!base) {
1800 fErrors.error(swizzle.fOffset, "unable to retrieve lvalue from swizzle");
1801 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001802 if (count == 1) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001803 IntLiteral index(fContext, -1, swizzle.components()[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001804 SpvId member = this->nextId();
1805 this->writeInstruction(SpvOpAccessChain,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001806 this->getPointerType(type,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001807 get_storage_class(*swizzle.base())),
Greg Daniel64773e62016-11-22 09:44:03 -05001808 member,
1809 base,
1810 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001811 out);
John Stiles5570c512020-11-19 17:58:07 -05001812 return std::make_unique<PointerLValue>(*this, member, this->getType(type),
1813 precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001814 } else {
John Stiles5570c512020-11-19 17:58:07 -05001815 return std::make_unique<SwizzleLValue>(*this, base, swizzle.components(),
1816 swizzle.base()->type(), type, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001817 }
1818 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001819 case Expression::Kind::kTernary: {
Ethan Nicholasa583b812018-01-18 13:32:11 -05001820 TernaryExpression& t = (TernaryExpression&) expr;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001821 SpvId test = this->writeExpression(*t.test(), out);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001822 SpvId end = this->nextId();
1823 SpvId ifTrueLabel = this->nextId();
1824 SpvId ifFalseLabel = this->nextId();
1825 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1826 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1827 this->writeLabel(ifTrueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04001828 SpvId ifTrue = this->getLValue(*t.ifTrue(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001829 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001830 this->writeInstruction(SpvOpBranch, end, out);
1831 ifTrueLabel = fCurrentBlock;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001832 SpvId ifFalse = this->getLValue(*t.ifFalse(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001833 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001834 ifFalseLabel = fCurrentBlock;
1835 this->writeInstruction(SpvOpBranch, end, out);
1836 SpvId result = this->nextId();
1837 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1838 ifTrueLabel, ifFalse, ifFalseLabel, out);
John Stiles5570c512020-11-19 17:58:07 -05001839 return std::make_unique<PointerLValue>(*this, result, this->getType(type), precision);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001840 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001841 default: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001842 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001843 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001844 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1845 // caught by IRGenerator
1846 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001847 SpvId pointerType = this->getPointerType(type, SpvStorageClassFunction);
1848 this->writeInstruction(SpvOpVariable, pointerType, result, SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001849 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001850 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
John Stiles5570c512020-11-19 17:58:07 -05001851 return std::make_unique<PointerLValue>(*this, result, this->getType(type), precision);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001852 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001853 }
1854}
1855
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001856SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001857 SpvId result = this->nextId();
Ethan Nicholas78686922020-10-08 06:46:27 -04001858 auto entry = fVariableMap.find(ref.variable());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001859 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001860 SpvId var = entry->second;
Ethan Nicholas78686922020-10-08 06:46:27 -04001861 this->writeInstruction(SpvOpLoad, this->getType(ref.variable()->type()), result, var, out);
1862 this->writePrecisionModifier(ref.variable()->type(), result);
1863 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
Greg Daniela85e4bf2020-06-17 16:32:45 -04001864 (fProgram.fSettings.fFlipY || fProgram.fSettings.fInverseW)) {
1865 // The x component never changes, so just grab it
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001866 SpvId xId = this->nextId();
1867 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1868 result, 0, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001869
1870 // Calculate the y component which may need to be flipped
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001871 SpvId rawYId = this->nextId();
1872 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1873 result, 1, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001874 SpvId flippedYId = 0;
1875 if (fProgram.fSettings.fFlipY) {
1876 // need to remap to a top-left coordinate system
1877 if (fRTHeightStructId == (SpvId)-1) {
1878 // height variable hasn't been written yet
Greg Daniela85e4bf2020-06-17 16:32:45 -04001879 SkASSERT(fRTHeightFieldIndex == (SpvId)-1);
1880 std::vector<Type::Field> fields;
John Stiles5570c512020-11-19 17:58:07 -05001881 if (fProgram.fSettings.fRTHeightOffset < 0) {
1882 fErrors.error(ref.fOffset, "RTHeightOffset is negative");
1883 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001884 fields.emplace_back(
1885 Modifiers(Layout(0, -1, fProgram.fSettings.fRTHeightOffset, -1, -1, -1, -1,
1886 -1, Layout::Format::kUnspecified,
1887 Layout::kUnspecified_Primitive, 1, -1, "", "",
1888 Layout::kNo_Key, Layout::CType::kDefault),
1889 0),
1890 SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1891 StringFragment name("sksl_synthetic_uniforms");
1892 Type intfStruct(-1, name, fields);
1893
1894 int binding = fProgram.fSettings.fRTHeightBinding;
John Stiles5570c512020-11-19 17:58:07 -05001895 if (binding == -1) {
1896 fErrors.error(ref.fOffset, "layout(binding=...) is required in SPIR-V");
1897 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001898 int set = fProgram.fSettings.fRTHeightSet;
John Stiles5570c512020-11-19 17:58:07 -05001899 if (set == -1) {
1900 fErrors.error(ref.fOffset, "layout(set=...) is required in SPIR-V");
1901 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001902 Layout layout(0, -1, -1, binding, -1, set, -1, -1, Layout::Format::kUnspecified,
1903 Layout::kUnspecified_Primitive, -1, -1, "", "", Layout::kNo_Key,
1904 Layout::CType::kDefault);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001905 Modifiers modifiers(layout, Modifiers::kUniform_Flag);
John Stiles3ae071e2020-08-05 15:29:29 -04001906 const Variable* intfVar = fSynthetics.takeOwnershipOfSymbol(
1907 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -05001908 fProgram.fModifiers->addToPool(modifiers),
John Stiles3ae071e2020-08-05 15:29:29 -04001909 name,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001910 &intfStruct,
Brian Osman3887a012020-09-30 13:22:27 -04001911 /*builtin=*/false,
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001912 Variable::Storage::kGlobal));
John Stilesd39aec02020-12-03 10:42:26 -05001913 InterfaceBlock intf(/*offset=*/-1, intfVar, name,
1914 /*instanceName=*/"", /*arraySize=*/0,
John Stiles7c3515b2020-10-16 18:38:39 -04001915 std::make_shared<SymbolTable>(&fErrors, /*builtin=*/false));
Stephen White88574972020-06-23 19:09:29 -04001916
1917 fRTHeightStructId = this->writeInterfaceBlock(intf, false);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001918 fRTHeightFieldIndex = 0;
Jim Van Verthf3ec9832020-10-21 16:09:57 -04001919 fRTHeightStorageClass = SpvStorageClassUniform;
Greg Daniela85e4bf2020-06-17 16:32:45 -04001920 }
1921 SkASSERT(fRTHeightFieldIndex != (SpvId)-1);
1922
1923 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1924 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1925 SpvId heightPtr = this->nextId();
1926 this->writeOpCode(SpvOpAccessChain, 5, out);
Jim Van Verthf3ec9832020-10-21 16:09:57 -04001927 this->writeWord(this->getPointerType(*fContext.fFloat_Type, fRTHeightStorageClass),
Greg Daniela85e4bf2020-06-17 16:32:45 -04001928 out);
1929 this->writeWord(heightPtr, out);
1930 this->writeWord(fRTHeightStructId, out);
1931 this->writeWord(fieldIndexId, out);
1932 SpvId heightRead = this->nextId();
1933 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1934 heightPtr, out);
1935
1936 flippedYId = this->nextId();
1937 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
1938 heightRead, rawYId, out);
1939 }
1940
1941 // The z component will always be zero so we just get an id to the 0 literal
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001942 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001943 SpvId zeroId = writeFloatLiteral(zero);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001944
1945 // Calculate the w component which may need to be inverted
1946 SpvId rawWId = this->nextId();
1947 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawWId,
Ethan Nicholas20798e52018-12-04 12:30:50 -05001948 result, 3, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001949 SpvId invWId = 0;
1950 if (fProgram.fSettings.fInverseW) {
1951 // We need to invert w
1952 FloatLiteral one(fContext, -1, 1.0);
1953 SpvId oneId = writeFloatLiteral(one);
1954 invWId = this->nextId();
1955 this->writeInstruction(SpvOpFDiv, this->getType(*fContext.fFloat_Type), invWId, oneId,
1956 rawWId, out);
1957 }
1958
1959 // Fill in the new fragcoord with the components from above
1960 SpvId adjusted = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001961 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001962 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001963 this->writeWord(adjusted, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001964 this->writeWord(xId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001965 if (fProgram.fSettings.fFlipY) {
1966 this->writeWord(flippedYId, out);
1967 } else {
1968 this->writeWord(rawYId, out);
1969 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001970 this->writeWord(zeroId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001971 if (fProgram.fSettings.fInverseW) {
1972 this->writeWord(invWId, out);
1973 } else {
1974 this->writeWord(rawWId, out);
1975 }
1976
1977 return adjusted;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001978 }
Ethan Nicholas78686922020-10-08 06:46:27 -04001979 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
Chris Daltonb91c4662018-08-01 10:46:22 -06001980 !fProgram.fSettings.fFlipY) {
1981 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1982 // the default convention of "counter-clockwise face is front".
1983 SpvId inverse = this->nextId();
1984 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1985 result, out);
1986 return inverse;
1987 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001988 return result;
1989}
1990
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001991SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05001992 if (expr.base()->type().isVector()) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001993 SpvId base = this->writeExpression(*expr.base(), out);
1994 SpvId index = this->writeExpression(*expr.index(), out);
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001995 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001996 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.type()), result, base,
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001997 index, out);
1998 return result;
1999 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002000 return getLValue(expr, out)->load(out);
2001}
2002
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002003SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002004 return getLValue(f, out)->load(out);
2005}
2006
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002007SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002008 SpvId base = this->writeExpression(*swizzle.base(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002009 SpvId result = this->nextId();
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002010 size_t count = swizzle.components().size();
ethannicholasb3058bd2016-07-01 08:22:01 -07002011 if (count == 1) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002012 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.type()), result, base,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002013 swizzle.components()[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002014 } else {
2015 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002016 this->writeWord(this->getType(swizzle.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002017 this->writeWord(result, out);
2018 this->writeWord(base, out);
Brian Osman25647672020-09-15 15:16:56 -04002019 this->writeWord(base, out);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002020 for (int component : swizzle.components()) {
Brian Osman25647672020-09-15 15:16:56 -04002021 this->writeWord(component, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002022 }
2023 }
2024 return result;
2025}
2026
Greg Daniel64773e62016-11-22 09:44:03 -05002027SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
2028 const Type& operandType, SpvId lhs,
2029 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002030 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002031 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002032 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002033 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002034 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002035 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002036 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002037 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
John Stiles123501f2020-12-09 10:08:13 -05002038 } else if (is_bool(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002039 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002040 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07002041 } else {
John Stiles123501f2020-12-09 10:08:13 -05002042 fErrors.error(operandType.fOffset,
2043 "unsupported operand for binary expression: " + operandType.description());
2044 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002045 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04002046 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002047 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
2048 fDecorationBuffer);
2049 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002050 return result;
2051}
2052
Ethan Nicholas48e24052018-03-14 13:51:39 -04002053SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
2054 OutputStream& out) {
John Stiles9aeed132020-11-24 17:36:06 -05002055 if (operandType.isVector()) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002056 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04002057 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002058 return result;
2059 }
2060 return id;
2061}
2062
Ethan Nicholas68990be2017-07-13 09:36:52 -04002063SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
2064 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002065 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04002066 OutputStream& out) {
2067 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
John Stiles9aeed132020-11-24 17:36:06 -05002068 SkASSERT(operandType.isMatrix());
Ethan Nicholas0df21132018-07-10 09:37:51 -04002069 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2070 operandType.rows(),
2071 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04002072 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002073 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04002074 1));
2075 SpvId boolType = this->getType(*fContext.fBool_Type);
2076 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04002077 for (int i = 0; i < operandType.columns(); i++) {
2078 SpvId columnL = this->nextId();
2079 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2080 SpvId columnR = this->nextId();
2081 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002082 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002083 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
2084 SpvId merge = this->nextId();
2085 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002086 if (result != 0) {
2087 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002088 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002089 result = next;
2090 }
2091 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002092 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04002093 }
2094 }
2095 return result;
2096}
2097
Ethan Nicholas0df21132018-07-10 09:37:51 -04002098SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
2099 SpvId rhs, SpvOp_ floatOperator,
2100 SpvOp_ intOperator,
2101 OutputStream& out) {
2102 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
John Stiles9aeed132020-11-24 17:36:06 -05002103 SkASSERT(operandType.isMatrix());
Ethan Nicholas0df21132018-07-10 09:37:51 -04002104 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2105 operandType.rows(),
2106 1));
2107 SpvId columns[4];
2108 for (int i = 0; i < operandType.columns(); i++) {
2109 SpvId columnL = this->nextId();
2110 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2111 SpvId columnR = this->nextId();
2112 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2113 columns[i] = this->nextId();
2114 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2115 }
2116 SpvId result = this->nextId();
2117 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2118 this->writeWord(this->getType(operandType), out);
2119 this->writeWord(result, out);
2120 for (int i = 0; i < operandType.columns(); i++) {
2121 this->writeWord(columns[i], out);
2122 }
2123 return result;
2124}
2125
Ethan Nicholas49465b42019-04-17 12:22:21 -04002126std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2127 if (type.isInteger()) {
2128 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002129 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002130 else if (type.isFloat()) {
2131 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002132 } else {
Ethan Nicholase2c49992020-10-05 11:49:11 -04002133 ABORT("math is unsupported on type '%s'", String(type.name()).c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002134 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002135}
2136
2137SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Token::Kind op,
2138 const Type& rightType, SpvId rhs,
2139 const Type& resultType, OutputStream& out) {
John Stilesd0614f22020-12-09 11:11:41 -05002140 // The comma operator ignores the type of the left-hand side entirely.
2141 if (op == Token::Kind::TK_COMMA) {
2142 return rhs;
2143 }
Ethan Nicholas48e24052018-03-14 13:51:39 -04002144 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002145 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002146 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2147 // handling in SPIR-V
Ethan Nicholas49465b42019-04-17 12:22:21 -04002148 if (this->getActualType(leftType) != this->getActualType(rightType)) {
John Stiles9aeed132020-11-24 17:36:06 -05002149 if (leftType.isVector() && rightType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002150 if (op == Token::Kind::TK_SLASH) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002151 SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
2152 SpvId inverse = this->nextId();
2153 this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
2154 rhs = inverse;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002155 op = Token::Kind::TK_STAR;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002156 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002157 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002158 SpvId result = this->nextId();
2159 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2160 result, lhs, rhs, out);
2161 return result;
2162 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002163 // promote number to vector
2164 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002165 const Type& vecType = leftType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002166 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2167 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002168 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002169 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002170 this->writeWord(rhs, out);
2171 }
2172 rhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002173 operandType = &leftType;
John Stiles9aeed132020-11-24 17:36:06 -05002174 } else if (rightType.isVector() && leftType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002175 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002176 SpvId result = this->nextId();
2177 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2178 result, rhs, lhs, out);
2179 return result;
2180 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002181 // promote number to vector
2182 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002183 const Type& vecType = rightType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002184 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2185 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002186 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002187 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002188 this->writeWord(lhs, out);
2189 }
2190 lhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002191 operandType = &rightType;
John Stiles9aeed132020-11-24 17:36:06 -05002192 } else if (leftType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002193 SpvOp_ spvop;
John Stiles9aeed132020-11-24 17:36:06 -05002194 if (rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002195 spvop = SpvOpMatrixTimesMatrix;
John Stiles9aeed132020-11-24 17:36:06 -05002196 } else if (rightType.isVector()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002197 spvop = SpvOpMatrixTimesVector;
ethannicholasb3058bd2016-07-01 08:22:01 -07002198 } else {
John Stiles9aeed132020-11-24 17:36:06 -05002199 SkASSERT(rightType.isScalar());
Ethan Nicholas49465b42019-04-17 12:22:21 -04002200 spvop = SpvOpMatrixTimesScalar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002201 }
2202 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002203 this->writeInstruction(spvop, this->getType(resultType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002204 return result;
John Stiles9aeed132020-11-24 17:36:06 -05002205 } else if (rightType.isMatrix()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002206 SpvId result = this->nextId();
John Stiles9aeed132020-11-24 17:36:06 -05002207 if (leftType.isVector()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002208 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(resultType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002209 lhs, rhs, out);
2210 } else {
John Stiles9aeed132020-11-24 17:36:06 -05002211 SkASSERT(leftType.isScalar());
Ethan Nicholas49465b42019-04-17 12:22:21 -04002212 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(resultType), result,
2213 rhs, lhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002214 }
2215 return result;
2216 } else {
John Stilesd8ca6b62020-11-23 14:28:36 -05002217 fErrors.error(leftType.fOffset, "unsupported mixed-type expression");
Ethan Nicholas49465b42019-04-17 12:22:21 -04002218 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002219 }
2220 } else {
John Stiles2d4f9592020-10-30 10:29:12 -04002221 operandType = &this->getActualType(leftType);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002222 SkASSERT(*operandType == this->getActualType(rightType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002223 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002224 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002225 case Token::Kind::TK_EQEQ: {
John Stiles9aeed132020-11-24 17:36:06 -05002226 if (operandType->isMatrix()) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002227 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002228 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002229 }
John Stiles4a7dc462020-11-25 11:08:08 -05002230 SkASSERT(resultType.isBoolean());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002231 const Type* tmpType;
John Stiles9aeed132020-11-24 17:36:06 -05002232 if (operandType->isVector()) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002233 tmpType = &fContext.fBool_Type->toCompound(fContext,
2234 operandType->columns(),
2235 operandType->rows());
2236 } else {
2237 tmpType = &resultType;
2238 }
2239 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002240 SpvOpFOrdEqual, SpvOpIEqual,
2241 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002242 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002243 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002244 case Token::Kind::TK_NEQ:
John Stiles9aeed132020-11-24 17:36:06 -05002245 if (operandType->isMatrix()) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002246 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002247 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002248 }
John Stiles4a7dc462020-11-25 11:08:08 -05002249 [[fallthrough]];
2250 case Token::Kind::TK_LOGICALXOR:
2251 SkASSERT(resultType.isBoolean());
Ethan Nicholas48e24052018-03-14 13:51:39 -04002252 const Type* tmpType;
John Stiles9aeed132020-11-24 17:36:06 -05002253 if (operandType->isVector()) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002254 tmpType = &fContext.fBool_Type->toCompound(fContext,
2255 operandType->columns(),
2256 operandType->rows());
2257 } else {
2258 tmpType = &resultType;
2259 }
2260 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002261 SpvOpFOrdNotEqual, SpvOpINotEqual,
2262 SpvOpINotEqual, SpvOpLogicalNotEqual,
2263 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002264 *operandType, SpvOpAny, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002265 case Token::Kind::TK_GT:
John Stiles4a7dc462020-11-25 11:08:08 -05002266 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002267 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2268 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002269 SpvOpUGreaterThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002270 case Token::Kind::TK_LT:
John Stiles4a7dc462020-11-25 11:08:08 -05002271 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002272 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002273 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002274 case Token::Kind::TK_GTEQ:
John Stiles4a7dc462020-11-25 11:08:08 -05002275 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002276 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2277 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002278 SpvOpUGreaterThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002279 case Token::Kind::TK_LTEQ:
John Stiles4a7dc462020-11-25 11:08:08 -05002280 SkASSERT(resultType.isBoolean());
Greg Daniel64773e62016-11-22 09:44:03 -05002281 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2282 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002283 SpvOpULessThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002284 case Token::Kind::TK_PLUS:
John Stiles9aeed132020-11-24 17:36:06 -05002285 if (leftType.isMatrix() && rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002286 SkASSERT(leftType == rightType);
2287 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002288 SpvOpFAdd, SpvOpIAdd, out);
2289 }
Greg Daniel64773e62016-11-22 09:44:03 -05002290 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002291 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002292 case Token::Kind::TK_MINUS:
John Stiles9aeed132020-11-24 17:36:06 -05002293 if (leftType.isMatrix() && rightType.isMatrix()) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002294 SkASSERT(leftType == rightType);
2295 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002296 SpvOpFSub, SpvOpISub, out);
2297 }
Greg Daniel64773e62016-11-22 09:44:03 -05002298 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002299 SpvOpISub, SpvOpISub, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002300 case Token::Kind::TK_STAR:
John Stiles9aeed132020-11-24 17:36:06 -05002301 if (leftType.isMatrix() && rightType.isMatrix()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002302 // matrix multiply
2303 SpvId result = this->nextId();
2304 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2305 lhs, rhs, out);
2306 return result;
2307 }
Greg Daniel64773e62016-11-22 09:44:03 -05002308 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002309 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002310 case Token::Kind::TK_SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002311 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002312 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002313 case Token::Kind::TK_PERCENT:
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002314 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2315 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002316 case Token::Kind::TK_SHL:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002317 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2318 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2319 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002320 case Token::Kind::TK_SHR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002321 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2322 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2323 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002324 case Token::Kind::TK_BITWISEAND:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002325 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2326 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002327 case Token::Kind::TK_BITWISEOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002328 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2329 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002330 case Token::Kind::TK_BITWISEXOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002331 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2332 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002333 default:
John Stiles5570c512020-11-19 17:58:07 -05002334 fErrors.error(0, "unsupported token");
Ethan Nicholas49465b42019-04-17 12:22:21 -04002335 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002336 }
2337}
2338
Ethan Nicholas49465b42019-04-17 12:22:21 -04002339SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
John Stiles2d4f9592020-10-30 10:29:12 -04002340 const Expression& left = *b.left();
2341 const Expression& right = *b.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002342 Token::Kind op = b.getOperator();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002343 // handle cases where we don't necessarily evaluate both LHS and RHS
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002344 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002345 case Token::Kind::TK_EQ: {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002346 SpvId rhs = this->writeExpression(right, out);
2347 this->getLValue(left, out)->store(rhs, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002348 return rhs;
2349 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002350 case Token::Kind::TK_LOGICALAND:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002351 return this->writeLogicalAnd(b, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002352 case Token::Kind::TK_LOGICALOR:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002353 return this->writeLogicalOr(b, out);
2354 default:
2355 break;
2356 }
2357
2358 std::unique_ptr<LValue> lvalue;
2359 SpvId lhs;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002360 if (Compiler::IsAssignment(op)) {
2361 lvalue = this->getLValue(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002362 lhs = lvalue->load(out);
2363 } else {
2364 lvalue = nullptr;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002365 lhs = this->writeExpression(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002366 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002367 SpvId rhs = this->writeExpression(right, out);
2368 SpvId result = this->writeBinaryExpression(left.type(), lhs, Compiler::RemoveAssignment(op),
2369 right.type(), rhs, b.type(), out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002370 if (lvalue) {
2371 lvalue->store(result, out);
2372 }
2373 return result;
2374}
2375
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002376SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002377 SkASSERT(a.getOperator() == Token::Kind::TK_LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002378 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002379 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
John Stiles2d4f9592020-10-30 10:29:12 -04002380 SpvId lhs = this->writeExpression(*a.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002381 SpvId rhsLabel = this->nextId();
2382 SpvId end = this->nextId();
2383 SpvId lhsBlock = fCurrentBlock;
2384 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2385 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2386 this->writeLabel(rhsLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04002387 SpvId rhs = this->writeExpression(*a.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002388 SpvId rhsBlock = fCurrentBlock;
2389 this->writeInstruction(SpvOpBranch, end, out);
2390 this->writeLabel(end, out);
2391 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002392 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002393 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002394 return result;
2395}
2396
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002397SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002398 SkASSERT(o.getOperator() == Token::Kind::TK_LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002399 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002400 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
John Stiles2d4f9592020-10-30 10:29:12 -04002401 SpvId lhs = this->writeExpression(*o.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002402 SpvId rhsLabel = this->nextId();
2403 SpvId end = this->nextId();
2404 SpvId lhsBlock = fCurrentBlock;
2405 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2406 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2407 this->writeLabel(rhsLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04002408 SpvId rhs = this->writeExpression(*o.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002409 SpvId rhsBlock = fCurrentBlock;
2410 this->writeInstruction(SpvOpBranch, end, out);
2411 this->writeLabel(end, out);
2412 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002413 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002414 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002415 return result;
2416}
2417
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002418SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002419 const Type& type = t.type();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002420 SpvId test = this->writeExpression(*t.test(), out);
2421 if (t.ifTrue()->type().columns() == 1 &&
2422 t.ifTrue()->isCompileTimeConstant() &&
2423 t.ifFalse()->isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002424 // both true and false are constants, can just use OpSelect
2425 SpvId result = this->nextId();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002426 SpvId trueId = this->writeExpression(*t.ifTrue(), out);
2427 SpvId falseId = this->writeExpression(*t.ifFalse(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002428 this->writeInstruction(SpvOpSelect, this->getType(type), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002429 out);
2430 return result;
2431 }
Greg Daniel64773e62016-11-22 09:44:03 -05002432 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002433 // Adreno. Switched to storing the result in a temp variable as glslang does.
2434 SpvId var = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002435 this->writeInstruction(SpvOpVariable, this->getPointerType(type, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002436 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002437 SpvId trueLabel = this->nextId();
2438 SpvId falseLabel = this->nextId();
2439 SpvId end = this->nextId();
2440 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2441 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2442 this->writeLabel(trueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002443 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifTrue(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002444 this->writeInstruction(SpvOpBranch, end, out);
2445 this->writeLabel(falseLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002446 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifFalse(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002447 this->writeInstruction(SpvOpBranch, end, out);
2448 this->writeLabel(end, out);
2449 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002450 this->writeInstruction(SpvOpLoad, this->getType(type), result, var, out);
2451 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002452 return result;
2453}
2454
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002455SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002456 const Type& type = p.type();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002457 if (p.getOperator() == Token::Kind::TK_MINUS) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002458 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002459 SpvId typeId = this->getType(type);
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002460 SpvId expr = this->writeExpression(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002461 if (is_float(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002462 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002463 } else if (is_signed(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002464 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2465 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002466#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002467 ABORT("unsupported prefix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002468#endif
Brian Salomon23356442018-11-30 15:33:19 -05002469 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002470 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002471 return result;
2472 }
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002473 switch (p.getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002474 case Token::Kind::TK_PLUS:
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002475 return this->writeExpression(*p.operand(), out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002476 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002477 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002478 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
2479 SpvId result = this->writeBinaryOperation(type, type, lv->load(out), one,
Greg Daniel64773e62016-11-22 09:44:03 -05002480 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002481 out);
2482 lv->store(result, out);
2483 return result;
2484 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002485 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002486 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002487 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
2488 SpvId result = this->writeBinaryOperation(type, type, lv->load(out), one, SpvOpFSub,
2489 SpvOpISub, SpvOpISub, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002490 lv->store(result, out);
2491 return result;
2492 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002493 case Token::Kind::TK_LOGICALNOT: {
John Stiles4a7dc462020-11-25 11:08:08 -05002494 SkASSERT(p.operand()->type().isBoolean());
ethannicholasb3058bd2016-07-01 08:22:01 -07002495 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002496 this->writeInstruction(SpvOpLogicalNot, this->getType(type), result,
2497 this->writeExpression(*p.operand(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002498 return result;
2499 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002500 case Token::Kind::TK_BITWISENOT: {
ethannicholas5961bc92016-10-12 06:39:56 -07002501 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002502 this->writeInstruction(SpvOpNot, this->getType(type), result,
2503 this->writeExpression(*p.operand(), out), out);
ethannicholas5961bc92016-10-12 06:39:56 -07002504 return result;
2505 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002506 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002507#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002508 ABORT("unsupported prefix expression: %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002509#endif
2510 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002511 }
2512}
2513
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002514SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002515 const Type& type = p.type();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002516 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002517 SpvId result = lv->load(out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002518 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002519 switch (p.getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002520 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002521 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002522 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2523 lv->store(temp, out);
2524 return result;
2525 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002526 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002527 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002528 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2529 lv->store(temp, out);
2530 return result;
2531 }
2532 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002533#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002534 ABORT("unsupported postfix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002535#endif
2536 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002537 }
2538}
2539
ethannicholasf789b382016-08-03 12:43:36 -07002540SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
Ethan Nicholas59d660c2020-09-28 09:18:15 -04002541 if (b.value()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002542 if (fBoolTrue == 0) {
2543 fBoolTrue = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002544 this->writeInstruction(SpvOpConstantTrue, this->getType(b.type()), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002545 fConstantBuffer);
2546 }
2547 return fBoolTrue;
2548 } else {
2549 if (fBoolFalse == 0) {
2550 fBoolFalse = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002551 this->writeInstruction(SpvOpConstantFalse, this->getType(b.type()), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002552 fConstantBuffer);
2553 }
2554 return fBoolFalse;
2555 }
2556}
2557
ethannicholasf789b382016-08-03 12:43:36 -07002558SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002559 const Type& type = i.type();
2560 ConstantType constantType;
John Stilesfd41d872020-11-25 22:39:45 -05002561 if (type == *fContext.fInt_Type || type.typeKind() == Type::TypeKind::kEnum) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002562 constantType = ConstantType::kInt;
2563 } else if (type == *fContext.fUInt_Type) {
2564 constantType = ConstantType::kUInt;
2565 } else if (type == *fContext.fShort_Type || type == *fContext.fByte_Type) {
2566 constantType = ConstantType::kShort;
2567 } else if (type == *fContext.fUShort_Type || type == *fContext.fUByte_Type) {
2568 constantType = ConstantType::kUShort;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002569 } else {
2570 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002571 }
Ethan Nicholase96cdd12020-09-28 16:27:18 -04002572 std::pair<ConstantValue, ConstantType> key(i.value(), constantType);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002573 auto entry = fNumberConstants.find(key);
2574 if (entry == fNumberConstants.end()) {
2575 SpvId result = this->nextId();
Ethan Nicholase96cdd12020-09-28 16:27:18 -04002576 this->writeInstruction(SpvOpConstant, this->getType(type), result, (SpvId) i.value(),
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002577 fConstantBuffer);
2578 fNumberConstants[key] = result;
2579 return result;
2580 }
2581 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002582}
2583
ethannicholasf789b382016-08-03 12:43:36 -07002584SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002585 const Type& type = f.type();
2586 ConstantType constantType;
2587 if (type == *fContext.fHalf_Type) {
2588 constantType = ConstantType::kHalf;
ethannicholasb3058bd2016-07-01 08:22:01 -07002589 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002590 constantType = ConstantType::kFloat;
ethannicholasb3058bd2016-07-01 08:22:01 -07002591 }
Ethan Nicholasa3f22f12020-10-01 12:13:17 -04002592 float value = (float) f.value();
2593 std::pair<ConstantValue, ConstantType> key(f.value(), constantType);
John Stiles8c578662020-06-01 15:32:47 +00002594 auto entry = fNumberConstants.find(key);
2595 if (entry == fNumberConstants.end()) {
2596 SpvId result = this->nextId();
2597 uint32_t bits;
2598 SkASSERT(sizeof(bits) == sizeof(value));
2599 memcpy(&bits, &value, sizeof(bits));
Ethan Nicholas30d30222020-09-11 12:27:26 -04002600 this->writeInstruction(SpvOpConstant, this->getType(type), result, bits,
John Stiles8c578662020-06-01 15:32:47 +00002601 fConstantBuffer);
2602 fNumberConstants[key] = result;
2603 return result;
2604 }
2605 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002606}
2607
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002608SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002609 SpvId result = fFunctionMap[&f];
Ethan Nicholased84b732020-10-08 11:45:44 -04002610 this->writeInstruction(SpvOpFunction, this->getType(f.returnType()), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002611 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04002612 this->writeInstruction(SpvOpName, result, f.name(), fNameBuffer);
Brian Osman5bf3e202020-10-13 10:34:18 -04002613 const std::vector<const Variable*>& parameters = f.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -04002614 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002615 SpvId id = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -04002616 fVariableMap[parameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002617 SpvId type;
Ethan Nicholased84b732020-10-08 11:45:44 -04002618 type = this->getPointerType(parameters[i]->type(), SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002619 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2620 }
2621 return result;
2622}
2623
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002624SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2625 fVariableBuffer.reset();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002626 SpvId result = this->writeFunctionStart(f.declaration(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002627 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002628 StringStream bodyBuffer;
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002629 this->writeBlock((Block&) *f.body(), bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002630 write_stringstream(fVariableBuffer, out);
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002631 if (f.declaration().name() == "main") {
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002632 write_stringstream(fGlobalInitializersBuffer, out);
2633 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002634 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002635 if (fCurrentBlock) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002636 if (f.declaration().returnType() == *fContext.fVoid_Type) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002637 this->writeInstruction(SpvOpReturn, out);
2638 } else {
2639 this->writeInstruction(SpvOpUnreachable, out);
2640 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002641 }
2642 this->writeInstruction(SpvOpFunctionEnd, out);
2643 return result;
2644}
2645
2646void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2647 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002648 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002649 fDecorationBuffer);
2650 }
2651 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002652 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002653 fDecorationBuffer);
2654 }
2655 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002656 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002657 fDecorationBuffer);
2658 }
2659 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002660 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002661 fDecorationBuffer);
2662 }
Greg Daniel64773e62016-11-22 09:44:03 -05002663 if (layout.fInputAttachmentIndex >= 0) {
2664 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2665 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002666 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002667 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002668 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002669 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002670 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002671 fDecorationBuffer);
2672 }
2673}
2674
2675void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2676 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002677 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002678 layout.fLocation, fDecorationBuffer);
2679 }
2680 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002681 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002682 layout.fBinding, fDecorationBuffer);
2683 }
2684 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002685 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002686 layout.fIndex, fDecorationBuffer);
2687 }
2688 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002689 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002690 layout.fSet, fDecorationBuffer);
2691 }
Greg Daniel64773e62016-11-22 09:44:03 -05002692 if (layout.fInputAttachmentIndex >= 0) {
2693 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2694 layout.fInputAttachmentIndex, fDecorationBuffer);
2695 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002696 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002697 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002698 layout.fBuiltin, fDecorationBuffer);
2699 }
2700}
2701
Ethan Nicholas81d15112018-07-13 12:48:50 -04002702static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2703 switch (m.fLayout.fPrimitive) {
2704 case Layout::kPoints_Primitive:
2705 *outSkInCount = 1;
2706 break;
2707 case Layout::kLines_Primitive:
2708 *outSkInCount = 2;
2709 break;
2710 case Layout::kLinesAdjacency_Primitive:
2711 *outSkInCount = 4;
2712 break;
2713 case Layout::kTriangles_Primitive:
2714 *outSkInCount = 3;
2715 break;
2716 case Layout::kTrianglesAdjacency_Primitive:
2717 *outSkInCount = 6;
2718 break;
2719 default:
2720 return;
2721 }
2722}
2723
Stephen White88574972020-06-23 19:09:29 -04002724SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf, bool appendRTHeight) {
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002725 bool isBuffer = ((intf.variable().modifiers().fFlags & Modifiers::kBuffer_Flag) != 0);
2726 bool pushConstant = ((intf.variable().modifiers().fLayout.fFlags &
2727 Layout::kPushConstant_Flag) != 0);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002728 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2729 MemoryLayout(MemoryLayout::k430_Standard) :
2730 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002731 SpvId result = this->nextId();
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002732 const Type* type = &intf.variable().type();
John Stiles21f5f452020-11-30 09:57:59 -05002733 if (!MemoryLayout::LayoutIsSupported(*type)) {
John Stiles0023c0c2020-11-16 13:32:18 -05002734 fErrors.error(type->fOffset, "type '" + type->name() + "' is not permitted here");
2735 return this->nextId();
2736 }
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002737 Modifiers intfModifiers = intf.variable().modifiers();
2738 SpvStorageClass_ storageClass = get_storage_class(intfModifiers);
Stephen White88574972020-06-23 19:09:29 -04002739 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Greg Daniele6ab9982018-08-22 13:56:32 +00002740 SkASSERT(fRTHeightStructId == (SpvId) -1);
2741 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002742 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002743 fRTHeightStructId = result;
2744 fRTHeightFieldIndex = fields.size();
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002745 fRTHeightStorageClass = storageClass;
Greg Daniele6ab9982018-08-22 13:56:32 +00002746 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002747 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002748 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002749 SpvId typeId;
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002750 if (intfModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osman133724c2020-10-28 14:14:39 -04002751 for (const ProgramElement* e : fProgram.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04002752 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04002753 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholas81d15112018-07-13 12:48:50 -04002754 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002755 }
2756 }
Ethan Nicholase6592142020-09-08 10:22:09 -04002757 typeId = this->getType(Type("sk_in", Type::TypeKind::kArray,
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002758 intf.variable().type().componentType(),
Ethan Nicholase6592142020-09-08 10:22:09 -04002759 fSkInCount),
2760 memoryLayout);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002761 } else {
2762 typeId = this->getType(*type, memoryLayout);
2763 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002764 if (intfModifiers.fFlags & Modifiers::kBuffer_Flag) {
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002765 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002766 } else if (intfModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002767 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002768 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002769 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002770 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002771 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002772 Layout layout = intfModifiers.fLayout;
2773 if (intfModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002774 layout.fSet = 0;
2775 }
2776 this->writeLayout(layout, result);
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002777 fVariableMap[&intf.variable()] = result;
Stephen White88574972020-06-23 19:09:29 -04002778 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002779 delete type;
2780 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002781 return result;
2782}
2783
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002784void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002785 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2786}
2787
2788void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2789 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002790 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2791 }
2792}
2793
Brian Osman010ce6a2020-10-19 16:34:10 -04002794bool is_dead(const Variable& var, const ProgramUsage* usage) {
2795 ProgramUsage::VariableCounts counts = usage->get(var);
2796 if (counts.fRead || counts.fWrite) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002797 return false;
2798 }
2799 // not entirely sure what the rules are for when it's safe to elide interface variables, but it
2800 // causes various problems to elide some of them even when dead. But it also causes problems
2801 // *not* to elide sk_SampleMask when it's not being used.
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002802 if (!(var.modifiers().fFlags & (Modifiers::kIn_Flag |
2803 Modifiers::kOut_Flag |
2804 Modifiers::kUniform_Flag |
2805 Modifiers::kBuffer_Flag))) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002806 return true;
2807 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002808 return var.modifiers().fLayout.fBuiltin == SK_SAMPLEMASK_BUILTIN;
Chris Dalton2284aab2019-11-15 11:02:24 -07002809}
2810
ethannicholas5961bc92016-10-12 06:39:56 -07002811#define BUILTIN_IGNORE 9999
Brian Osmanc0213602020-10-06 14:43:32 -04002812void SPIRVCodeGenerator::writeGlobalVar(Program::Kind kind, const VarDeclaration& varDecl,
2813 OutputStream& out) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002814 const Variable& var = varDecl.var();
Brian Osmanc0213602020-10-06 14:43:32 -04002815 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2816 // in the OpenGL backend.
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002817 SkASSERT(!(var.modifiers().fFlags & (Modifiers::kReadOnly_Flag |
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002818 Modifiers::kWriteOnly_Flag |
2819 Modifiers::kCoherent_Flag |
2820 Modifiers::kVolatile_Flag |
2821 Modifiers::kRestrict_Flag)));
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002822 if (var.modifiers().fLayout.fBuiltin == BUILTIN_IGNORE) {
Brian Osmanc0213602020-10-06 14:43:32 -04002823 return;
2824 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002825 if (var.modifiers().fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
Brian Osmanc0213602020-10-06 14:43:32 -04002826 kind != Program::kFragment_Kind) {
2827 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
2828 return;
2829 }
Brian Osman010ce6a2020-10-19 16:34:10 -04002830 if (is_dead(var, fProgram.fUsage.get())) {
Brian Osmanc0213602020-10-06 14:43:32 -04002831 return;
2832 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002833 const Type& type = var.type();
Brian Osmanc0213602020-10-06 14:43:32 -04002834 SpvStorageClass_ storageClass;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002835 if (var.modifiers().fFlags & Modifiers::kIn_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002836 storageClass = SpvStorageClassInput;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002837 } else if (var.modifiers().fFlags & Modifiers::kOut_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002838 storageClass = SpvStorageClassOutput;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002839 } else if (var.modifiers().fFlags & Modifiers::kUniform_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002840 if (type.typeKind() == Type::TypeKind::kSampler ||
2841 type.typeKind() == Type::TypeKind::kSeparateSampler ||
2842 type.typeKind() == Type::TypeKind::kTexture) {
2843 storageClass = SpvStorageClassUniformConstant;
ethannicholasb3058bd2016-07-01 08:22:01 -07002844 } else {
Brian Osmanc0213602020-10-06 14:43:32 -04002845 storageClass = SpvStorageClassUniform;
ethannicholasb3058bd2016-07-01 08:22:01 -07002846 }
Brian Osmanc0213602020-10-06 14:43:32 -04002847 } else {
2848 storageClass = SpvStorageClassPrivate;
2849 }
2850 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002851 fVariableMap[&var] = id;
Brian Osmanc0213602020-10-06 14:43:32 -04002852 SpvId typeId;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002853 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osmanc0213602020-10-06 14:43:32 -04002854 typeId = this->getPointerType(
2855 Type("sk_in", Type::TypeKind::kArray, type.componentType(), fSkInCount),
2856 storageClass);
2857 } else {
2858 typeId = this->getPointerType(type, storageClass);
2859 }
2860 this->writeInstruction(SpvOpVariable, typeId, id, storageClass, fConstantBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002861 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002862 this->writePrecisionModifier(type, id);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002863 if (varDecl.value()) {
Brian Osmanc0213602020-10-06 14:43:32 -04002864 SkASSERT(!fCurrentBlock);
2865 fCurrentBlock = -1;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002866 SpvId value = this->writeExpression(*varDecl.value(), fGlobalInitializersBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002867 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
2868 fCurrentBlock = 0;
2869 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002870 this->writeLayout(var.modifiers().fLayout, id);
2871 if (var.modifiers().fFlags & Modifiers::kFlat_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002872 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2873 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002874 if (var.modifiers().fFlags & Modifiers::kNoPerspective_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002875 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2876 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002877 }
2878}
2879
Brian Osmanc0213602020-10-06 14:43:32 -04002880void SPIRVCodeGenerator::writeVarDeclaration(const VarDeclaration& varDecl, OutputStream& out) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002881 const Variable& var = varDecl.var();
Brian Osmanc0213602020-10-06 14:43:32 -04002882 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2883 // in the OpenGL backend.
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002884 SkASSERT(!(var.modifiers().fFlags & (Modifiers::kReadOnly_Flag |
2885 Modifiers::kWriteOnly_Flag |
2886 Modifiers::kCoherent_Flag |
2887 Modifiers::kVolatile_Flag |
2888 Modifiers::kRestrict_Flag)));
Brian Osmanc0213602020-10-06 14:43:32 -04002889 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002890 fVariableMap[&var] = id;
2891 SpvId type = this->getPointerType(var.type(), SpvStorageClassFunction);
Brian Osmanc0213602020-10-06 14:43:32 -04002892 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002893 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
2894 if (varDecl.value()) {
2895 SpvId value = this->writeExpression(*varDecl.value(), out);
Brian Osmanc0213602020-10-06 14:43:32 -04002896 this->writeInstruction(SpvOpStore, id, value, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002897 }
2898}
2899
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002900void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002901 switch (s.kind()) {
John Stiles98c1f822020-09-09 14:18:53 -04002902 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04002903 case Statement::Kind::kNop:
Ethan Nicholascb670962017-04-20 19:31:52 -04002904 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002905 case Statement::Kind::kBlock:
ethannicholasb3058bd2016-07-01 08:22:01 -07002906 this->writeBlock((Block&) s, out);
2907 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002908 case Statement::Kind::kExpression:
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04002909 this->writeExpression(*s.as<ExpressionStatement>().expression(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002910 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002911 case Statement::Kind::kReturn:
John Stiles26f98502020-08-18 09:30:51 -04002912 this->writeReturnStatement(s.as<ReturnStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002913 break;
Brian Osmanc0213602020-10-06 14:43:32 -04002914 case Statement::Kind::kVarDeclaration:
2915 this->writeVarDeclaration(s.as<VarDeclaration>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002916 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002917 case Statement::Kind::kIf:
John Stiles26f98502020-08-18 09:30:51 -04002918 this->writeIfStatement(s.as<IfStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002919 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002920 case Statement::Kind::kFor:
John Stiles26f98502020-08-18 09:30:51 -04002921 this->writeForStatement(s.as<ForStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002922 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002923 case Statement::Kind::kWhile:
John Stiles26f98502020-08-18 09:30:51 -04002924 this->writeWhileStatement(s.as<WhileStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002925 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002926 case Statement::Kind::kDo:
John Stiles26f98502020-08-18 09:30:51 -04002927 this->writeDoStatement(s.as<DoStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002928 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002929 case Statement::Kind::kSwitch:
John Stiles26f98502020-08-18 09:30:51 -04002930 this->writeSwitchStatement(s.as<SwitchStatement>(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002931 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002932 case Statement::Kind::kBreak:
ethannicholasb3058bd2016-07-01 08:22:01 -07002933 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2934 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002935 case Statement::Kind::kContinue:
ethannicholasb3058bd2016-07-01 08:22:01 -07002936 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2937 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002938 case Statement::Kind::kDiscard:
ethannicholasb3058bd2016-07-01 08:22:01 -07002939 this->writeInstruction(SpvOpKill, out);
2940 break;
2941 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002942#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002943 ABORT("unsupported statement: %s", s.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002944#endif
2945 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002946 }
2947}
2948
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002949void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04002950 for (const std::unique_ptr<Statement>& stmt : b.children()) {
2951 this->writeStatement(*stmt, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002952 }
2953}
2954
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002955void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002956 SpvId test = this->writeExpression(*stmt.test(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002957 SpvId ifTrue = this->nextId();
2958 SpvId ifFalse = this->nextId();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002959 if (stmt.ifFalse()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002960 SpvId end = this->nextId();
2961 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2962 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2963 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002964 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002965 if (fCurrentBlock) {
2966 this->writeInstruction(SpvOpBranch, end, out);
2967 }
2968 this->writeLabel(ifFalse, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002969 this->writeStatement(*stmt.ifFalse(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002970 if (fCurrentBlock) {
2971 this->writeInstruction(SpvOpBranch, end, out);
2972 }
2973 this->writeLabel(end, out);
2974 } else {
2975 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2976 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2977 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002978 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002979 if (fCurrentBlock) {
2980 this->writeInstruction(SpvOpBranch, ifFalse, out);
2981 }
2982 this->writeLabel(ifFalse, out);
2983 }
2984}
2985
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002986void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04002987 if (f.initializer()) {
2988 this->writeStatement(*f.initializer(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002989 }
2990 SpvId header = this->nextId();
2991 SpvId start = this->nextId();
2992 SpvId body = this->nextId();
2993 SpvId next = this->nextId();
2994 fContinueTarget.push(next);
2995 SpvId end = this->nextId();
2996 fBreakTarget.push(end);
2997 this->writeInstruction(SpvOpBranch, header, out);
2998 this->writeLabel(header, out);
2999 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07003000 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003001 this->writeLabel(start, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003002 if (f.test()) {
3003 SpvId test = this->writeExpression(*f.test(), out);
ethannicholas22f939e2016-10-13 13:25:34 -07003004 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
3005 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003006 this->writeLabel(body, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003007 this->writeStatement(*f.statement(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003008 if (fCurrentBlock) {
3009 this->writeInstruction(SpvOpBranch, next, out);
3010 }
3011 this->writeLabel(next, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04003012 if (f.next()) {
3013 this->writeExpression(*f.next(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003014 }
3015 this->writeInstruction(SpvOpBranch, header, out);
3016 this->writeLabel(end, out);
3017 fBreakTarget.pop();
3018 fContinueTarget.pop();
3019}
3020
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003021void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003022 SpvId header = this->nextId();
3023 SpvId start = this->nextId();
3024 SpvId body = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003025 SpvId continueTarget = this->nextId();
3026 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003027 SpvId end = this->nextId();
3028 fBreakTarget.push(end);
3029 this->writeInstruction(SpvOpBranch, header, out);
3030 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003031 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003032 this->writeInstruction(SpvOpBranch, start, out);
3033 this->writeLabel(start, out);
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003034 SpvId test = this->writeExpression(*w.test(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003035 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
3036 this->writeLabel(body, out);
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003037 this->writeStatement(*w.statement(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003038 if (fCurrentBlock) {
Ethan Nicholas0d997662019-04-08 09:46:01 -04003039 this->writeInstruction(SpvOpBranch, continueTarget, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003040 }
Ethan Nicholas0d997662019-04-08 09:46:01 -04003041 this->writeLabel(continueTarget, out);
3042 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003043 this->writeLabel(end, out);
3044 fBreakTarget.pop();
3045 fContinueTarget.pop();
3046}
3047
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003048void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003049 SpvId header = this->nextId();
3050 SpvId start = this->nextId();
3051 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003052 SpvId continueTarget = this->nextId();
3053 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003054 SpvId end = this->nextId();
3055 fBreakTarget.push(end);
3056 this->writeInstruction(SpvOpBranch, header, out);
3057 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003058 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003059 this->writeInstruction(SpvOpBranch, start, out);
3060 this->writeLabel(start, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003061 this->writeStatement(*d.statement(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003062 if (fCurrentBlock) {
3063 this->writeInstruction(SpvOpBranch, next, out);
3064 }
3065 this->writeLabel(next, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003066 SpvId test = this->writeExpression(*d.test(), out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003067 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
3068 this->writeLabel(continueTarget, out);
3069 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003070 this->writeLabel(end, out);
3071 fBreakTarget.pop();
3072 fContinueTarget.pop();
3073}
3074
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003075void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04003076 SpvId value = this->writeExpression(*s.value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003077 std::vector<SpvId> labels;
3078 SpvId end = this->nextId();
3079 SpvId defaultLabel = end;
3080 fBreakTarget.push(end);
3081 int size = 3;
John Stiles2d4f9592020-10-30 10:29:12 -04003082 auto& cases = s.cases();
3083 for (const std::unique_ptr<SwitchCase>& c : cases) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003084 SpvId label = this->nextId();
3085 labels.push_back(label);
John Stiles2d4f9592020-10-30 10:29:12 -04003086 if (c->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003087 size += 2;
3088 } else {
3089 defaultLabel = label;
3090 }
3091 }
3092 labels.push_back(end);
3093 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3094 this->writeOpCode(SpvOpSwitch, size, out);
3095 this->writeWord(value, out);
3096 this->writeWord(defaultLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04003097 for (size_t i = 0; i < cases.size(); ++i) {
3098 if (!cases[i]->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003099 continue;
3100 }
John Stiles2d4f9592020-10-30 10:29:12 -04003101 this->writeWord(cases[i]->value()->as<IntLiteral>().value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003102 this->writeWord(labels[i], out);
3103 }
John Stiles2d4f9592020-10-30 10:29:12 -04003104 for (size_t i = 0; i < cases.size(); ++i) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003105 this->writeLabel(labels[i], out);
John Stiles2d4f9592020-10-30 10:29:12 -04003106 for (const auto& stmt : cases[i]->statements()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003107 this->writeStatement(*stmt, out);
3108 }
3109 if (fCurrentBlock) {
3110 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3111 }
3112 }
3113 this->writeLabel(end, out);
3114 fBreakTarget.pop();
3115}
3116
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003117void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003118 if (r.expression()) {
3119 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.expression(), out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003120 out);
3121 } else {
3122 this->writeInstruction(SpvOpReturn, out);
3123 }
3124}
3125
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003126void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003127 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003128 int invocations = 1;
Brian Osman133724c2020-10-28 14:14:39 -04003129 for (const ProgramElement* e : fProgram.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003130 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04003131 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003132 if (m.fFlags & Modifiers::kIn_Flag) {
3133 if (m.fLayout.fInvocations != -1) {
3134 invocations = m.fLayout.fInvocations;
3135 }
3136 SpvId input;
3137 switch (m.fLayout.fPrimitive) {
3138 case Layout::kPoints_Primitive:
3139 input = SpvExecutionModeInputPoints;
3140 break;
3141 case Layout::kLines_Primitive:
3142 input = SpvExecutionModeInputLines;
3143 break;
3144 case Layout::kLinesAdjacency_Primitive:
3145 input = SpvExecutionModeInputLinesAdjacency;
3146 break;
3147 case Layout::kTriangles_Primitive:
3148 input = SpvExecutionModeTriangles;
3149 break;
3150 case Layout::kTrianglesAdjacency_Primitive:
3151 input = SpvExecutionModeInputTrianglesAdjacency;
3152 break;
3153 default:
3154 input = 0;
3155 break;
3156 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003157 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003158 if (input) {
3159 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3160 }
3161 } else if (m.fFlags & Modifiers::kOut_Flag) {
3162 SpvId output;
3163 switch (m.fLayout.fPrimitive) {
3164 case Layout::kPoints_Primitive:
3165 output = SpvExecutionModeOutputPoints;
3166 break;
3167 case Layout::kLineStrip_Primitive:
3168 output = SpvExecutionModeOutputLineStrip;
3169 break;
3170 case Layout::kTriangleStrip_Primitive:
3171 output = SpvExecutionModeOutputTriangleStrip;
3172 break;
3173 default:
3174 output = 0;
3175 break;
3176 }
3177 if (output) {
3178 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3179 }
3180 if (m.fLayout.fMaxVertices != -1) {
3181 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3182 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3183 out);
3184 }
3185 }
3186 }
3187 }
3188 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3189 invocations, out);
3190}
3191
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003192void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003193 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003194 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003195 std::set<SpvId> interfaceVars;
Brian Osman1f8f5752020-10-28 14:46:21 -04003196 // assign IDs to functions
Brian Osman133724c2020-10-28 14:14:39 -04003197 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003198 switch (e->kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04003199 case ProgramElement::Kind::kFunction: {
Brian Osman1179fcf2020-10-08 16:04:40 -04003200 const FunctionDefinition& f = e->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04003201 fFunctionMap[&f.declaration()] = this->nextId();
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003202 break;
3203 }
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003204 default:
3205 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003206 }
3207 }
Brian Osman133724c2020-10-28 14:14:39 -04003208 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003209 if (e->is<InterfaceBlock>()) {
Brian Osman1f8f5752020-10-28 14:46:21 -04003210 const InterfaceBlock& intf = e->as<InterfaceBlock>();
ethannicholasb3058bd2016-07-01 08:22:01 -07003211 SpvId id = this->writeInterfaceBlock(intf);
Brian Osman1f8f5752020-10-28 14:46:21 -04003212
3213 const Modifiers& modifiers = intf.variable().modifiers();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003214 if (((modifiers.fFlags & Modifiers::kIn_Flag) ||
3215 (modifiers.fFlags & Modifiers::kOut_Flag)) &&
3216 modifiers.fLayout.fBuiltin == -1 &&
Brian Osman010ce6a2020-10-19 16:34:10 -04003217 !is_dead(intf.variable(), fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003218 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003219 }
3220 }
3221 }
Brian Osman133724c2020-10-28 14:14:39 -04003222 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003223 if (e->is<GlobalVarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04003224 this->writeGlobalVar(program.fKind,
3225 e->as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>(),
3226 body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003227 }
3228 }
Brian Osman133724c2020-10-28 14:14:39 -04003229 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003230 if (e->is<FunctionDefinition>()) {
3231 this->writeFunction(e->as<FunctionDefinition>(), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003232 }
3233 }
ethannicholasd598f792016-07-25 10:08:54 -07003234 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003235 for (auto entry : fFunctionMap) {
Ethan Nicholase2c49992020-10-05 11:49:11 -04003236 if (entry.first->name() == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003237 main = entry.first;
3238 }
3239 }
Ethan Nicholas1a668d22019-04-18 10:37:40 -04003240 if (!main) {
3241 fErrors.error(0, "program does not contain a main() function");
3242 return;
3243 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003244 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003245 const Variable* var = entry.first;
Ethan Nicholas453f67f2020-10-09 10:43:45 -04003246 if (var->storage() == Variable::Storage::kGlobal &&
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003247 ((var->modifiers().fFlags & Modifiers::kIn_Flag) ||
Brian Osman010ce6a2020-10-19 16:34:10 -04003248 (var->modifiers().fFlags & Modifiers::kOut_Flag)) &&
3249 !is_dead(*var, fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003250 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003251 }
3252 }
3253 this->writeCapabilities(out);
3254 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3255 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003256 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->name().fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003257 (int32_t) interfaceVars.size(), out);
3258 switch (program.fKind) {
3259 case Program::kVertex_Kind:
3260 this->writeWord(SpvExecutionModelVertex, out);
3261 break;
3262 case Program::kFragment_Kind:
3263 this->writeWord(SpvExecutionModelFragment, out);
3264 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003265 case Program::kGeometry_Kind:
3266 this->writeWord(SpvExecutionModelGeometry, out);
3267 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003268 default:
3269 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003270 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003271 SpvId entryPoint = fFunctionMap[main];
3272 this->writeWord(entryPoint, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003273 this->writeString(main->name().fChars, main->name().fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003274 for (int var : interfaceVars) {
3275 this->writeWord(var, out);
3276 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003277 if (program.fKind == Program::kGeometry_Kind) {
3278 this->writeGeometryShaderExecutionMode(entryPoint, out);
3279 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003280 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003281 this->writeInstruction(SpvOpExecutionMode,
3282 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003283 SpvExecutionModeOriginUpperLeft,
3284 out);
3285 }
Brian Osman133724c2020-10-28 14:14:39 -04003286 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003287 if (e->is<Extension>()) {
3288 this->writeInstruction(SpvOpSourceExtension, e->as<Extension>().name().c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003289 }
3290 }
Greg Daniel64773e62016-11-22 09:44:03 -05003291
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003292 write_stringstream(fExtraGlobalsBuffer, out);
3293 write_stringstream(fNameBuffer, out);
3294 write_stringstream(fDecorationBuffer, out);
3295 write_stringstream(fConstantBuffer, out);
3296 write_stringstream(fExternalFunctionsBuffer, out);
3297 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003298}
3299
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003300bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003301 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003302 this->writeWord(SpvMagicNumber, *fOut);
3303 this->writeWord(SpvVersion, *fOut);
3304 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003305 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003306 this->writeInstructions(fProgram, buffer);
3307 this->writeWord(fIdCount, *fOut);
3308 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003309 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003310 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003311}
3312
John Stilesa6841be2020-08-06 14:11:56 -04003313} // namespace SkSL