blob: 7d67e9c423be8f2ad3b447c6d99deb7d57de2b9e [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);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040069 fIntrinsicMap[String("inversesqrt")] = ALL_GLSL(InverseSqrt);
70 fIntrinsicMap[String("determinant")] = ALL_GLSL(Determinant);
71 fIntrinsicMap[String("matrixInverse")] = ALL_GLSL(MatrixInverse);
Ethan Nicholas70a44b22017-11-30 09:09:16 -050072 fIntrinsicMap[String("mod")] = SPECIAL(Mod);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050073 fIntrinsicMap[String("min")] = SPECIAL(Min);
74 fIntrinsicMap[String("max")] = SPECIAL(Max);
75 fIntrinsicMap[String("clamp")] = SPECIAL(Clamp);
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -040076 fIntrinsicMap[String("saturate")] = SPECIAL(Saturate);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040077 fIntrinsicMap[String("dot")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
Ethan Nicholas0187ae62017-05-03 11:03:44 -040078 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -050079 fIntrinsicMap[String("mix")] = SPECIAL(Mix);
Brian Osman6ba3be12020-11-13 16:32:52 -050080 fIntrinsicMap[String("step")] = SPECIAL(Step);
81 fIntrinsicMap[String("smoothstep")] = SPECIAL(SmoothStep);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040082 fIntrinsicMap[String("fma")] = ALL_GLSL(Fma);
83 fIntrinsicMap[String("frexp")] = ALL_GLSL(Frexp);
84 fIntrinsicMap[String("ldexp")] = ALL_GLSL(Ldexp);
ethannicholasb3058bd2016-07-01 08:22:01 -070085
Ethan Nicholas0df1b042017-03-31 13:56:23 -040086#define PACK(type) fIntrinsicMap[String("pack" #type)] = ALL_GLSL(Pack ## type); \
87 fIntrinsicMap[String("unpack" #type)] = ALL_GLSL(Unpack ## type)
ethannicholasb3058bd2016-07-01 08:22:01 -070088 PACK(Snorm4x8);
89 PACK(Unorm4x8);
90 PACK(Snorm2x16);
91 PACK(Unorm2x16);
92 PACK(Half2x16);
93 PACK(Double2x32);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040094 fIntrinsicMap[String("length")] = ALL_GLSL(Length);
95 fIntrinsicMap[String("distance")] = ALL_GLSL(Distance);
96 fIntrinsicMap[String("cross")] = ALL_GLSL(Cross);
97 fIntrinsicMap[String("normalize")] = ALL_GLSL(Normalize);
98 fIntrinsicMap[String("faceForward")] = ALL_GLSL(FaceForward);
99 fIntrinsicMap[String("reflect")] = ALL_GLSL(Reflect);
100 fIntrinsicMap[String("refract")] = ALL_GLSL(Refract);
101 fIntrinsicMap[String("findLSB")] = ALL_GLSL(FindILsb);
102 fIntrinsicMap[String("findMSB")] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
103 fIntrinsicMap[String("dFdx")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400104 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700105 fIntrinsicMap[String("dFdy")] = SPECIAL(DFdy);
Chris Dalton09212192018-11-13 15:07:24 -0500106 fIntrinsicMap[String("fwidth")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFwidth,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400107 SpvOpUndef, SpvOpUndef, SpvOpUndef);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400108 fIntrinsicMap[String("makeSampler2D")] = SPECIAL(SampledImage);
109
Ethan Nicholas13863662019-07-29 13:05:15 -0400110 fIntrinsicMap[String("sample")] = SPECIAL(Texture);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400111 fIntrinsicMap[String("subpassLoad")] = SPECIAL(SubpassLoad);
Greg Daniel64773e62016-11-22 09:44:03 -0500112
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400113 fIntrinsicMap[String("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400114 SpvOpUndef, SpvOpUndef, SpvOpAny);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400115 fIntrinsicMap[String("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400116 SpvOpUndef, SpvOpUndef, SpvOpAll);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400117 fIntrinsicMap[String("equal")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400118 SpvOpFOrdEqual, SpvOpIEqual,
119 SpvOpIEqual, SpvOpLogicalEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400120 fIntrinsicMap[String("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400121 SpvOpFOrdNotEqual, SpvOpINotEqual,
122 SpvOpINotEqual,
123 SpvOpLogicalNotEqual);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400124 fIntrinsicMap[String("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500125 SpvOpFOrdLessThan, SpvOpSLessThan,
126 SpvOpULessThan, SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400127 fIntrinsicMap[String("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500128 SpvOpFOrdLessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400129 SpvOpSLessThanEqual,
130 SpvOpULessThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400131 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400132 fIntrinsicMap[String("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500133 SpvOpFOrdGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400134 SpvOpSGreaterThan,
135 SpvOpUGreaterThan,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400136 SpvOpUndef);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400137 fIntrinsicMap[String("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500138 SpvOpFOrdGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400139 SpvOpSGreaterThanEqual,
140 SpvOpUGreaterThanEqual,
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400141 SpvOpUndef);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400142 fIntrinsicMap[String("EmitVertex")] = ALL_SPIRV(EmitVertex);
143 fIntrinsicMap[String("EndPrimitive")] = ALL_SPIRV(EndPrimitive);
ethannicholasb3058bd2016-07-01 08:22:01 -0700144// interpolateAt* not yet supported...
145}
146
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400147void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700148 out.write((const char*) &word, sizeof(word));
ethannicholasb3058bd2016-07-01 08:22:01 -0700149}
150
ethannicholasd598f792016-07-25 10:08:54 -0700151static bool is_float(const Context& context, const Type& type) {
Ethan Nicholas0df21132018-07-10 09:37:51 -0400152 if (type.columns() > 1) {
ethannicholasd598f792016-07-25 10:08:54 -0700153 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700154 }
John Stiles8c578662020-06-01 15:32:47 +0000155 return type == *context.fFloat_Type || type == *context.fHalf_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700156}
157
ethannicholasd598f792016-07-25 10:08:54 -0700158static bool is_signed(const Context& context, const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400159 if (type.typeKind() == Type::TypeKind::kVector) {
ethannicholasd598f792016-07-25 10:08:54 -0700160 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700161 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400162 return type == *context.fInt_Type || type == *context.fShort_Type ||
163 type == *context.fByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700164}
165
ethannicholasd598f792016-07-25 10:08:54 -0700166static bool is_unsigned(const Context& context, const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400167 if (type.typeKind() == Type::TypeKind::kVector) {
ethannicholasd598f792016-07-25 10:08:54 -0700168 return is_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700169 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400170 return type == *context.fUInt_Type || type == *context.fUShort_Type ||
171 type == *context.fUByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700172}
173
ethannicholasd598f792016-07-25 10:08:54 -0700174static bool is_bool(const Context& context, const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400175 if (type.typeKind() == Type::TypeKind::kVector) {
ethannicholasd598f792016-07-25 10:08:54 -0700176 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700177 }
ethannicholasd598f792016-07-25 10:08:54 -0700178 return type == *context.fBool_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700179}
180
ethannicholasd598f792016-07-25 10:08:54 -0700181static bool is_out(const Variable& var) {
Ethan Nicholas041fd0a2020-10-07 16:42:04 -0400182 return (var.modifiers().fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700183}
184
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400185void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400186 SkASSERT(opCode != SpvOpLoad || &out != &fConstantBuffer);
187 SkASSERT(opCode != SpvOpUndef);
ethannicholasb3058bd2016-07-01 08:22:01 -0700188 switch (opCode) {
189 case SpvOpReturn: // fall through
190 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700191 case SpvOpKill: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700192 case SpvOpBranch: // fall through
193 case SpvOpBranchConditional:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400194 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700195 fCurrentBlock = 0;
196 break;
197 case SpvOpConstant: // fall through
198 case SpvOpConstantTrue: // fall through
199 case SpvOpConstantFalse: // fall through
200 case SpvOpConstantComposite: // fall through
201 case SpvOpTypeVoid: // fall through
202 case SpvOpTypeInt: // fall through
203 case SpvOpTypeFloat: // fall through
204 case SpvOpTypeBool: // fall through
205 case SpvOpTypeVector: // fall through
206 case SpvOpTypeMatrix: // fall through
207 case SpvOpTypeArray: // fall through
208 case SpvOpTypePointer: // fall through
209 case SpvOpTypeFunction: // fall through
210 case SpvOpTypeRuntimeArray: // fall through
211 case SpvOpTypeStruct: // fall through
212 case SpvOpTypeImage: // fall through
213 case SpvOpTypeSampledImage: // fall through
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400214 case SpvOpTypeSampler: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700215 case SpvOpVariable: // fall through
216 case SpvOpFunction: // fall through
217 case SpvOpFunctionParameter: // fall through
218 case SpvOpFunctionEnd: // fall through
219 case SpvOpExecutionMode: // fall through
220 case SpvOpMemoryModel: // fall through
221 case SpvOpCapability: // fall through
222 case SpvOpExtInstImport: // fall through
223 case SpvOpEntryPoint: // fall through
224 case SpvOpSource: // fall through
225 case SpvOpSourceExtension: // fall through
226 case SpvOpName: // fall through
227 case SpvOpMemberName: // fall through
228 case SpvOpDecorate: // fall through
229 case SpvOpMemberDecorate:
230 break;
231 default:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400232 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700233 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700234 this->writeWord((length << 16) | opCode, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700235}
236
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400237void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700238 fCurrentBlock = label;
239 this->writeInstruction(SpvOpLabel, label, out);
240}
241
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400242void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700243 this->writeOpCode(opCode, 1, out);
244}
245
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400246void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700247 this->writeOpCode(opCode, 2, out);
248 this->writeWord(word1, out);
249}
250
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700251void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputStream& out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400252 out.write(string, length);
ethannicholasb3058bd2016-07-01 08:22:01 -0700253 switch (length % 4) {
254 case 1:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500255 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400256 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700257 case 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500258 out.write8(0);
John Stiles30212b72020-06-11 17:55:07 -0400259 [[fallthrough]];
ethannicholasb3058bd2016-07-01 08:22:01 -0700260 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500261 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700262 break;
263 default:
264 this->writeWord(0, out);
265 }
266}
267
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700268void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out) {
269 this->writeOpCode(opCode, 1 + (string.fLength + 4) / 4, out);
270 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700271}
272
273
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700274void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400275 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700276 this->writeOpCode(opCode, 2 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700277 this->writeWord(word1, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700278 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700279}
280
Greg Daniel64773e62016-11-22 09:44:03 -0500281void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700282 StringFragment string, OutputStream& out) {
283 this->writeOpCode(opCode, 3 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700284 this->writeWord(word1, out);
285 this->writeWord(word2, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700286 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700287}
288
Greg Daniel64773e62016-11-22 09:44:03 -0500289void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400290 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700291 this->writeOpCode(opCode, 3, out);
292 this->writeWord(word1, out);
293 this->writeWord(word2, out);
294}
295
Greg Daniel64773e62016-11-22 09:44:03 -0500296void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400297 int32_t word3, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700298 this->writeOpCode(opCode, 4, out);
299 this->writeWord(word1, out);
300 this->writeWord(word2, out);
301 this->writeWord(word3, out);
302}
303
Greg Daniel64773e62016-11-22 09:44:03 -0500304void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400305 int32_t word3, int32_t word4, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700306 this->writeOpCode(opCode, 5, out);
307 this->writeWord(word1, out);
308 this->writeWord(word2, out);
309 this->writeWord(word3, out);
310 this->writeWord(word4, out);
311}
312
Greg Daniel64773e62016-11-22 09:44:03 -0500313void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
314 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400315 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700316 this->writeOpCode(opCode, 6, out);
317 this->writeWord(word1, out);
318 this->writeWord(word2, out);
319 this->writeWord(word3, out);
320 this->writeWord(word4, out);
321 this->writeWord(word5, out);
322}
323
Greg Daniel64773e62016-11-22 09:44:03 -0500324void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700325 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400326 int32_t word6, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700327 this->writeOpCode(opCode, 7, out);
328 this->writeWord(word1, out);
329 this->writeWord(word2, out);
330 this->writeWord(word3, out);
331 this->writeWord(word4, out);
332 this->writeWord(word5, out);
333 this->writeWord(word6, out);
334}
335
Greg Daniel64773e62016-11-22 09:44:03 -0500336void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700337 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400338 int32_t word6, int32_t word7, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700339 this->writeOpCode(opCode, 8, out);
340 this->writeWord(word1, out);
341 this->writeWord(word2, out);
342 this->writeWord(word3, out);
343 this->writeWord(word4, out);
344 this->writeWord(word5, out);
345 this->writeWord(word6, out);
346 this->writeWord(word7, out);
347}
348
Greg Daniel64773e62016-11-22 09:44:03 -0500349void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700350 int32_t word3, int32_t word4, int32_t word5,
351 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400352 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700353 this->writeOpCode(opCode, 9, out);
354 this->writeWord(word1, out);
355 this->writeWord(word2, out);
356 this->writeWord(word3, out);
357 this->writeWord(word4, out);
358 this->writeWord(word5, out);
359 this->writeWord(word6, out);
360 this->writeWord(word7, out);
361 this->writeWord(word8, out);
362}
363
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400364void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700365 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
366 if (fCapabilities & bit) {
367 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
368 }
369 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400370 if (fProgram.fKind == Program::kGeometry_Kind) {
371 this->writeInstruction(SpvOpCapability, SpvCapabilityGeometry, out);
372 }
Ethan Nicholas81d15112018-07-13 12:48:50 -0400373 else {
374 this->writeInstruction(SpvOpCapability, SpvCapabilityShader, out);
375 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700376}
377
378SpvId SPIRVCodeGenerator::nextId() {
379 return fIdCount++;
380}
381
Ethan Nicholas19671772016-11-28 16:30:17 -0500382void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
383 SpvId resultId) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400384 this->writeInstruction(SpvOpName, resultId, String(type.name()).c_str(), fNameBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700385 // go ahead and write all of the field types, so we don't inadvertently write them while we're
386 // in the middle of writing the struct instruction
387 std::vector<SpvId> types;
388 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500389 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700390 }
391 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
392 this->writeWord(resultId, fConstantBuffer);
393 for (SpvId id : types) {
394 this->writeWord(id, fConstantBuffer);
395 }
396 size_t offset = 0;
397 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400398 const Type::Field& field = type.fields()[i];
John Stiles0023c0c2020-11-16 13:32:18 -0500399 if (!memoryLayout.layoutIsSupported(*field.fType)) {
400 fErrors.error(type.fOffset, "type '" + field.fType->name() + "' is not permitted here");
401 return;
402 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400403 size_t size = memoryLayout.size(*field.fType);
404 size_t alignment = memoryLayout.alignment(*field.fType);
405 const Layout& fieldLayout = field.fModifiers.fLayout;
Ethan Nicholas19671772016-11-28 16:30:17 -0500406 if (fieldLayout.fOffset >= 0) {
Greg Danieldbd44c72017-01-24 15:12:12 -0500407 if (fieldLayout.fOffset < (int) offset) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700408 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400409 "offset of field '" + field.fName + "' must be at "
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500410 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -0500411 }
412 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700413 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400414 "offset of field '" + field.fName + "' must be a multiple"
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500415 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -0500416 }
417 offset = fieldLayout.fOffset;
418 } else {
419 size_t mod = offset % alignment;
420 if (mod) {
421 offset += alignment - mod;
422 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700423 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400424 this->writeInstruction(SpvOpMemberName, resultId, i, field.fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500425 this->writeLayout(fieldLayout, resultId, i);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400426 if (field.fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -0500427 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700428 (SpvId) offset, fDecorationBuffer);
429 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400430 if (field.fType->typeKind() == Type::TypeKind::kMatrix) {
Greg Daniel64773e62016-11-22 09:44:03 -0500431 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -0700432 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500433 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400434 (SpvId) memoryLayout.stride(*field.fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800435 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700436 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400437 if (!field.fType->highPrecision()) {
438 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i,
439 SpvDecorationRelaxedPrecision, fDecorationBuffer);
440 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700441 offset += size;
Ethan Nicholase6592142020-09-08 10:22:09 -0400442 Type::TypeKind kind = field.fType->typeKind();
443 if ((kind == Type::TypeKind::kArray || kind == Type::TypeKind::kStruct) &&
444 offset % alignment != 0) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700445 offset += alignment - offset % alignment;
446 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700447 }
448}
449
Ethan Nicholase2c49992020-10-05 11:49:11 -0400450const Type& SPIRVCodeGenerator::getActualType(const Type& type) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500451 if (type.isFloat()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400452 return *fContext.fFloat_Type;
453 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500454 if (type.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400455 return *fContext.fInt_Type;
456 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500457 if (type.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400458 return *fContext.fUInt_Type;
459 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400460 if (type.typeKind() == Type::TypeKind::kMatrix || type.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400461 if (type.componentType() == *fContext.fHalf_Type) {
462 return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
463 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400464 if (type.componentType() == *fContext.fShort_Type ||
465 type.componentType() == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400466 return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
467 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400468 if (type.componentType() == *fContext.fUShort_Type ||
469 type.componentType() == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400470 return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
471 }
472 }
473 return type;
474}
475
ethannicholasb3058bd2016-07-01 08:22:01 -0700476SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800477 return this->getType(type, fDefaultLayout);
478}
479
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400480SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400481 const Type& type = this->getActualType(rawType);
Jim Van Verthf3ec9832020-10-21 16:09:57 -0400482 String key = type.name();
483 if (type.typeKind() == Type::TypeKind::kStruct || type.typeKind() == Type::TypeKind::kArray) {
484 key += to_string((int)layout.fStd);
485 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800486 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700487 if (entry == fTypeMap.end()) {
488 SpvId result = this->nextId();
Ethan Nicholase6592142020-09-08 10:22:09 -0400489 switch (type.typeKind()) {
490 case Type::TypeKind::kScalar:
ethannicholasd598f792016-07-25 10:08:54 -0700491 if (type == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700492 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500493 } else if (type == *fContext.fInt_Type || type == *fContext.fShort_Type ||
494 type == *fContext.fIntLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700495 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500496 } else if (type == *fContext.fUInt_Type || type == *fContext.fUShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700497 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500498 } else if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type ||
499 type == *fContext.fFloatLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700500 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700501 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400502 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700503 }
504 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400505 case Type::TypeKind::kVector:
Greg Daniel64773e62016-11-22 09:44:03 -0500506 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800507 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700508 type.columns(), fConstantBuffer);
509 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400510 case Type::TypeKind::kMatrix:
Greg Daniel64773e62016-11-22 09:44:03 -0500511 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800512 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700513 type.columns(), fConstantBuffer);
514 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400515 case Type::TypeKind::kStruct:
ethannicholas8ac838d2016-11-22 08:39:36 -0800516 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700517 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400518 case Type::TypeKind::kArray: {
ethannicholasb3058bd2016-07-01 08:22:01 -0700519 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700520 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500521 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800522 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700523 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500524 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400525 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800526 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700527 } else {
John Stiles5570c512020-11-19 17:58:07 -0500528 // We shouldn't have any runtime-sized arrays right now
529 fErrors.error(type.fOffset, "runtime-sized arrays are not supported in SPIR-V");
Greg Daniel64773e62016-11-22 09:44:03 -0500530 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800531 this->getType(type.componentType(), layout),
532 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400533 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
534 (int32_t) layout.stride(type),
535 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700536 }
537 break;
538 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400539 case Type::TypeKind::kSampler: {
Greg Daniel64773e62016-11-22 09:44:03 -0500540 SpvId image = result;
541 if (SpvDimSubpassData != type.dimensions()) {
Stephen White792e2302019-08-09 13:33:51 -0400542 image = this->getType(type.textureType(), layout);
Greg Daniel64773e62016-11-22 09:44:03 -0500543 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400544 if (SpvDimBuffer == type.dimensions()) {
545 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
546 }
Greg Daniel64773e62016-11-22 09:44:03 -0500547 if (SpvDimSubpassData != type.dimensions()) {
548 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
549 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700550 break;
551 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400552 case Type::TypeKind::kSeparateSampler: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400553 this->writeInstruction(SpvOpTypeSampler, result, fConstantBuffer);
554 break;
555 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400556 case Type::TypeKind::kTexture: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400557 this->writeInstruction(SpvOpTypeImage, result,
558 this->getType(*fContext.fFloat_Type, layout),
Stephen White792e2302019-08-09 13:33:51 -0400559 type.dimensions(), type.isDepth(), type.isArrayed(),
560 type.isMultisampled(), type.isSampled() ? 1 : 2,
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400561 SpvImageFormatUnknown, fConstantBuffer);
562 fImageTypeMap[key] = result;
563 break;
564 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700565 default:
ethannicholasd598f792016-07-25 10:08:54 -0700566 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700567 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
568 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500569#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700570 ABORT("invalid type: %s", type.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500571#endif
ethannicholasb3058bd2016-07-01 08:22:01 -0700572 }
573 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800574 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700575 return result;
576 }
577 return entry->second;
578}
579
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400580SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400581 SkASSERT(type.typeKind() == Type::TypeKind::kSampler);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400582 this->getType(type);
583 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400584 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400585 return fImageTypeMap[key];
586}
587
ethannicholasd598f792016-07-25 10:08:54 -0700588SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400589 String key = to_string(this->getType(function.returnType())) + "(";
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400590 String separator;
Brian Osman5bf3e202020-10-13 10:34:18 -0400591 const std::vector<const Variable*>& parameters = function.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400592 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700593 key += separator;
594 separator = ", ";
Ethan Nicholased84b732020-10-08 11:45:44 -0400595 key += to_string(this->getType(parameters[i]->type()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700596 }
597 key += ")";
598 auto entry = fTypeMap.find(key);
599 if (entry == fTypeMap.end()) {
600 SpvId result = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -0400601 int32_t length = 3 + (int32_t) parameters.size();
602 SpvId returnType = this->getType(function.returnType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700603 std::vector<SpvId> parameterTypes;
Ethan Nicholased84b732020-10-08 11:45:44 -0400604 for (size_t i = 0; i < parameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500605 // glslang seems to treat all function arguments as pointers whether they need to be or
606 // not. I was initially puzzled by this until I ran bizarre failures with certain
607 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700608 // failure case:
609 //
610 // void sphere(float x) {
611 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500612 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700613 // void map() {
614 // sphere(1.0);
615 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500616 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700617 // void main() {
618 // for (int i = 0; i < 1; i++) {
619 // map();
620 // }
621 // }
622 //
Greg Daniel64773e62016-11-22 09:44:03 -0500623 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
624 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700625 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
626 // the spec makes this make sense.
627// if (is_out(function->fParameters[i])) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400628 parameterTypes.push_back(this->getPointerType(parameters[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -0700629 SpvStorageClassFunction));
630// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700631// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700632// }
633 }
634 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
635 this->writeWord(result, fConstantBuffer);
636 this->writeWord(returnType, fConstantBuffer);
637 for (SpvId id : parameterTypes) {
638 this->writeWord(id, fConstantBuffer);
639 }
640 fTypeMap[key] = result;
641 return result;
642 }
643 return entry->second;
644}
645
ethannicholas8ac838d2016-11-22 08:39:36 -0800646SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
647 return this->getPointerType(type, fDefaultLayout, storageClass);
648}
649
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400650SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700651 SpvStorageClass_ storageClass) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400652 const Type& type = this->getActualType(rawType);
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500653 String key = type.displayName() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700654 auto entry = fTypeMap.find(key);
655 if (entry == fTypeMap.end()) {
656 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500657 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700658 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700659 fTypeMap[key] = result;
660 return result;
661 }
662 return entry->second;
663}
664
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400665SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400666 switch (expr.kind()) {
667 case Expression::Kind::kBinary:
John Stiles81365af2020-08-18 09:24:00 -0400668 return this->writeBinaryExpression(expr.as<BinaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400669 case Expression::Kind::kBoolLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400670 return this->writeBoolLiteral(expr.as<BoolLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400671 case Expression::Kind::kConstructor:
John Stiles81365af2020-08-18 09:24:00 -0400672 return this->writeConstructor(expr.as<Constructor>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400673 case Expression::Kind::kIntLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400674 return this->writeIntLiteral(expr.as<IntLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400675 case Expression::Kind::kFieldAccess:
John Stiles81365af2020-08-18 09:24:00 -0400676 return this->writeFieldAccess(expr.as<FieldAccess>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400677 case Expression::Kind::kFloatLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400678 return this->writeFloatLiteral(expr.as<FloatLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400679 case Expression::Kind::kFunctionCall:
John Stiles81365af2020-08-18 09:24:00 -0400680 return this->writeFunctionCall(expr.as<FunctionCall>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400681 case Expression::Kind::kPrefix:
John Stiles81365af2020-08-18 09:24:00 -0400682 return this->writePrefixExpression(expr.as<PrefixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400683 case Expression::Kind::kPostfix:
John Stiles81365af2020-08-18 09:24:00 -0400684 return this->writePostfixExpression(expr.as<PostfixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400685 case Expression::Kind::kSwizzle:
John Stiles81365af2020-08-18 09:24:00 -0400686 return this->writeSwizzle(expr.as<Swizzle>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400687 case Expression::Kind::kVariableReference:
John Stiles81365af2020-08-18 09:24:00 -0400688 return this->writeVariableReference(expr.as<VariableReference>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400689 case Expression::Kind::kTernary:
John Stiles81365af2020-08-18 09:24:00 -0400690 return this->writeTernaryExpression(expr.as<TernaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400691 case Expression::Kind::kIndex:
John Stiles81365af2020-08-18 09:24:00 -0400692 return this->writeIndexExpression(expr.as<IndexExpression>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700693 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500694#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700695 ABORT("unsupported expression: %s", expr.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500696#endif
697 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700698 }
699 return -1;
700}
701
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400702SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400703 const FunctionDeclaration& function = c.function();
John Stiles8e3b6be2020-10-13 11:14:08 -0400704 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400705 auto intrinsic = fIntrinsicMap.find(function.name());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400706 SkASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -0700707 int32_t intrinsicId;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400708 if (arguments.size() > 0) {
709 const Type& type = arguments[0]->type();
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400710 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
711 intrinsicId = std::get<1>(intrinsic->second);
712 } else if (is_signed(fContext, type)) {
713 intrinsicId = std::get<2>(intrinsic->second);
714 } else if (is_unsigned(fContext, type)) {
715 intrinsicId = std::get<3>(intrinsic->second);
716 } else if (is_bool(fContext, type)) {
717 intrinsicId = std::get<4>(intrinsic->second);
718 } else {
719 intrinsicId = std::get<1>(intrinsic->second);
720 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700721 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400722 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700723 }
724 switch (std::get<0>(intrinsic->second)) {
725 case kGLSL_STD_450_IntrinsicKind: {
726 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400727 std::vector<SpvId> argumentIds;
728 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400729 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400730 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400731 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400732 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400733 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700734 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400735 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400736 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700737 this->writeWord(result, out);
738 this->writeWord(fGLSLExtendedInstructions, out);
739 this->writeWord(intrinsicId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400740 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700741 this->writeWord(id, out);
742 }
743 return result;
744 }
745 case kSPIRV_IntrinsicKind: {
Brian Osman46787d52020-11-24 14:18:23 -0500746 // GLSL supports dot(float, float), but SPIR-V does not. Convert it to FMul
747 if (intrinsicId == SpvOpDot &&
748 arguments[0]->type().typeKind() == Type::TypeKind::kScalar) {
749 intrinsicId = SpvOpFMul;
750 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700751 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400752 std::vector<SpvId> argumentIds;
753 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400754 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400755 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400756 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400757 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400758 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700759 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400760 if (c.type() != *fContext.fVoid_Type) {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400761 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400762 this->writeWord(this->getType(c.type()), out);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400763 this->writeWord(result, out);
764 } else {
765 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
766 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400767 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700768 this->writeWord(id, out);
769 }
770 return result;
771 }
772 case kSpecial_IntrinsicKind:
773 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
774 default:
775 ABORT("unsupported intrinsic kind");
776 }
777}
778
John Stiles8e3b6be2020-10-13 11:14:08 -0400779std::vector<SpvId> SPIRVCodeGenerator::vectorize(const ExpressionArray& args, OutputStream& out) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500780 int vectorSize = 0;
781 for (const auto& a : args) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400782 if (a->type().typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500783 if (vectorSize) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400784 SkASSERT(a->type().columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500785 }
786 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400787 vectorSize = a->type().columns();
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500788 }
789 }
790 }
791 std::vector<SpvId> result;
John Stiles8e3b6be2020-10-13 11:14:08 -0400792 result.reserve(args.size());
Ethan Nicholas30d30222020-09-11 12:27:26 -0400793 for (const auto& arg : args) {
794 const Type& argType = arg->type();
795 SpvId raw = this->writeExpression(*arg, out);
796 if (vectorSize && argType.typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500797 SpvId vector = this->nextId();
798 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400799 this->writeWord(this->getType(argType.toCompound(fContext, vectorSize, 1)), out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500800 this->writeWord(vector, out);
801 for (int i = 0; i < vectorSize; i++) {
802 this->writeWord(raw, out);
803 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400804 this->writePrecisionModifier(argType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500805 result.push_back(vector);
806 } else {
807 result.push_back(raw);
808 }
809 }
810 return result;
811}
812
813void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
814 SpvId signedInst, SpvId unsignedInst,
815 const std::vector<SpvId>& args,
816 OutputStream& out) {
817 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
818 this->writeWord(this->getType(type), out);
819 this->writeWord(id, out);
820 this->writeWord(fGLSLExtendedInstructions, out);
821
822 if (is_float(fContext, type)) {
823 this->writeWord(floatInst, out);
824 } else if (is_signed(fContext, type)) {
825 this->writeWord(signedInst, out);
826 } else if (is_unsigned(fContext, type)) {
827 this->writeWord(unsignedInst, out);
828 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400829 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500830 }
831 for (SpvId a : args) {
832 this->writeWord(a, out);
833 }
834}
835
Greg Daniel64773e62016-11-22 09:44:03 -0500836SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400837 OutputStream& out) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400838 const ExpressionArray& arguments = c.arguments();
ethannicholasb3058bd2016-07-01 08:22:01 -0700839 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400840 const Type& callType = c.type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700841 switch (kind) {
842 case kAtan_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400843 std::vector<SpvId> argumentIds;
844 for (const std::unique_ptr<Expression>& arg : arguments) {
845 argumentIds.push_back(this->writeExpression(*arg, out));
ethannicholasb3058bd2016-07-01 08:22:01 -0700846 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400847 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400848 this->writeWord(this->getType(callType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700849 this->writeWord(result, out);
850 this->writeWord(fGLSLExtendedInstructions, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400851 this->writeWord(argumentIds.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
852 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700853 this->writeWord(id, out);
854 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400855 break;
856 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400857 case kSampledImage_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400858 SkASSERT(arguments.size() == 2);
859 SpvId img = this->writeExpression(*arguments[0], out);
860 SpvId sampler = this->writeExpression(*arguments[1], out);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400861 this->writeInstruction(SpvOpSampledImage,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400862 this->getType(callType),
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400863 result,
864 img,
865 sampler,
866 out);
867 break;
868 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400869 case kSubpassLoad_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400870 SpvId img = this->writeExpression(*arguments[0], out);
John Stiles8e3b6be2020-10-13 11:14:08 -0400871 ExpressionArray args;
John Stilesf4bda742020-10-14 16:57:41 -0400872 args.reserve_back(2);
John Stiles8e3b6be2020-10-13 11:14:08 -0400873 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
874 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
Ethan Nicholas30d30222020-09-11 12:27:26 -0400875 Constructor ctor(-1, fContext.fInt2_Type.get(), std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400876 SpvId coords = this->writeConstantVector(ctor);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400877 if (arguments.size() == 1) {
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400878 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400879 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400880 result,
881 img,
882 coords,
883 out);
884 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400885 SkASSERT(arguments.size() == 2);
886 SpvId sample = this->writeExpression(*arguments[1], out);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400887 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400888 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400889 result,
890 img,
891 coords,
892 SpvImageOperandsSampleMask,
893 sample,
894 out);
895 }
896 break;
897 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700898 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500899 SpvOp_ op = SpvOpImageSampleImplicitLod;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400900 const Type& arg1Type = arguments[1]->type();
901 switch (arguments[0]->type().dimensions()) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500902 case SpvDim1D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400903 if (arg1Type == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500904 op = SpvOpImageSampleProjImplicitLod;
905 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400906 SkASSERT(arg1Type == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500907 }
908 break;
909 case SpvDim2D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400910 if (arg1Type == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500911 op = SpvOpImageSampleProjImplicitLod;
912 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400913 SkASSERT(arg1Type == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500914 }
915 break;
916 case SpvDim3D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400917 if (arg1Type == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500918 op = SpvOpImageSampleProjImplicitLod;
919 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400920 SkASSERT(arg1Type == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500921 }
922 break;
923 case SpvDimCube: // fall through
924 case SpvDimRect: // fall through
925 case SpvDimBuffer: // fall through
926 case SpvDimSubpassData:
927 break;
928 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400929 SpvId type = this->getType(callType);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400930 SpvId sampler = this->writeExpression(*arguments[0], out);
931 SpvId uv = this->writeExpression(*arguments[1], out);
932 if (arguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500933 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700934 SpvImageOperandsBiasMask,
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400935 this->writeExpression(*arguments[2], out),
ethannicholasb3058bd2016-07-01 08:22:01 -0700936 out);
937 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400938 SkASSERT(arguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500939 if (fProgram.fSettings.fSharpenTextures) {
940 FloatLiteral lodBias(fContext, -1, -0.5);
941 this->writeInstruction(op, type, result, sampler, uv,
942 SpvImageOperandsBiasMask,
943 this->writeFloatLiteral(lodBias),
944 out);
945 } else {
946 this->writeInstruction(op, type, result, sampler, uv,
947 out);
948 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700949 }
950 break;
951 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500952 case kMod_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400953 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400954 SkASSERT(args.size() == 2);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400955 const Type& operandType = arguments[0]->type();
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500956 SpvOp_ op;
957 if (is_float(fContext, operandType)) {
958 op = SpvOpFMod;
959 } else if (is_signed(fContext, operandType)) {
960 op = SpvOpSMod;
961 } else if (is_unsigned(fContext, operandType)) {
962 op = SpvOpUMod;
963 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400964 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500965 return 0;
966 }
967 this->writeOpCode(op, 5, out);
968 this->writeWord(this->getType(operandType), out);
969 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500970 this->writeWord(args[0], out);
971 this->writeWord(args[1], out);
972 break;
973 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700974 case kDFdy_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400975 SpvId fn = this->writeExpression(*arguments[0], out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700976 this->writeOpCode(SpvOpDPdy, 4, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400977 this->writeWord(this->getType(callType), out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700978 this->writeWord(result, out);
979 this->writeWord(fn, out);
980 if (fProgram.fSettings.fFlipY) {
981 // Flipping Y also negates the Y derivatives.
982 SpvId flipped = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400983 this->writeInstruction(SpvOpFNegate, this->getType(callType), flipped, result,
984 out);
985 this->writePrecisionModifier(callType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700986 return flipped;
987 }
988 break;
989 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500990 case kClamp_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400991 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400992 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400993 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500994 GLSLstd450UClamp, args, out);
995 break;
996 }
997 case kMax_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400998 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400999 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001000 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMax, GLSLstd450SMax,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001001 GLSLstd450UMax, args, out);
1002 break;
1003 }
1004 case kMin_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001005 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001006 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001007 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMin, GLSLstd450SMin,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001008 GLSLstd450UMin, args, out);
1009 break;
1010 }
1011 case kMix_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001012 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001013 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001014 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMix, SpvOpUndef,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001015 SpvOpUndef, args, out);
1016 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -05001017 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001018 case kSaturate_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001019 SkASSERT(arguments.size() == 1);
John Stiles8e3b6be2020-10-13 11:14:08 -04001020 ExpressionArray finalArgs;
John Stilesf4bda742020-10-14 16:57:41 -04001021 finalArgs.reserve_back(3);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001022 finalArgs.push_back(arguments[0]->clone());
John Stiles8e3b6be2020-10-13 11:14:08 -04001023 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1024 /*value=*/0));
1025 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1026 /*value=*/1));
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001027 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001028 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001029 GLSLstd450UClamp, spvArgs, out);
1030 break;
1031 }
Brian Osman6ba3be12020-11-13 16:32:52 -05001032 case kSmoothStep_SpecialIntrinsic: {
1033 std::vector<SpvId> args = this->vectorize(arguments, out);
1034 SkASSERT(args.size() == 3);
1035 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450SmoothStep, SpvOpUndef,
1036 SpvOpUndef, args, out);
1037 break;
1038 }
1039 case kStep_SpecialIntrinsic: {
1040 std::vector<SpvId> args = this->vectorize(arguments, out);
1041 SkASSERT(args.size() == 2);
1042 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450Step, SpvOpUndef,
1043 SpvOpUndef, args, out);
1044 break;
1045 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001046 }
1047 return result;
1048}
1049
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001050SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001051 const FunctionDeclaration& function = c.function();
John Stiles8e3b6be2020-10-13 11:14:08 -04001052 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001053 const auto& entry = fFunctionMap.find(&function);
ethannicholasb3058bd2016-07-01 08:22:01 -07001054 if (entry == fFunctionMap.end()) {
1055 return this->writeIntrinsicCall(c, out);
1056 }
1057 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001058 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001059 std::vector<SpvId> argumentIds;
1060 for (size_t i = 0; i < arguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001061 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001062 // passed directly
1063 SpvId tmpVar;
1064 // if we need a temporary var to store this argument, this is the value to store in the var
1065 SpvId tmpValueId;
Ethan Nicholased84b732020-10-08 11:45:44 -04001066 if (is_out(*function.parameters()[i])) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001067 std::unique_ptr<LValue> lv = this->getLValue(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001068 SpvId ptr = lv->getPointer();
1069 if (ptr) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001070 argumentIds.push_back(ptr);
ethannicholasb3058bd2016-07-01 08:22:01 -07001071 continue;
1072 } else {
1073 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1074 // copy it into a temp, call the function, read the value out of the temp, and then
1075 // update the lvalue.
1076 tmpValueId = lv->load(out);
1077 tmpVar = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001078 lvalues.push_back(std::make_tuple(tmpVar, &arguments[i]->type(), std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001079 }
1080 } else {
1081 // see getFunctionType for an explanation of why we're always using pointer parameters
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001082 tmpValueId = this->writeExpression(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001083 tmpVar = this->nextId();
1084 }
Greg Daniel64773e62016-11-22 09:44:03 -05001085 this->writeInstruction(SpvOpVariable,
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001086 this->getPointerType(arguments[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001087 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001088 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001089 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001090 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001091 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001092 argumentIds.push_back(tmpVar);
ethannicholasb3058bd2016-07-01 08:22:01 -07001093 }
1094 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001095 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001096 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001097 this->writeWord(result, out);
1098 this->writeWord(entry->second, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001099 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001100 this->writeWord(id, out);
1101 }
1102 // now that the call is complete, we may need to update some lvalues with the new values of out
1103 // arguments
1104 for (const auto& tuple : lvalues) {
1105 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001106 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1107 out);
1108 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001109 std::get<2>(tuple)->store(load, out);
1110 }
1111 return result;
1112}
1113
ethannicholasf789b382016-08-03 12:43:36 -07001114SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001115 const Type& type = c.type();
1116 SkASSERT(type.typeKind() == Type::TypeKind::kVector && c.isCompileTimeConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001117 SpvId result = this->nextId();
1118 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001119 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1120 arguments.push_back(this->writeExpression(*arg, fConstantBuffer));
ethannicholasb3058bd2016-07-01 08:22:01 -07001121 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001122 SpvId typeId = this->getType(type);
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001123 if (c.arguments().size() == 1) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001124 // with a single argument, a vector will have all of its entries equal to the argument
Ethan Nicholas30d30222020-09-11 12:27:26 -04001125 this->writeOpCode(SpvOpConstantComposite, 3 + type.columns(), fConstantBuffer);
1126 this->writeWord(typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001127 this->writeWord(result, fConstantBuffer);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001128 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001129 this->writeWord(arguments[0], fConstantBuffer);
1130 }
1131 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001132 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.arguments().size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001133 fConstantBuffer);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001134 this->writeWord(typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001135 this->writeWord(result, fConstantBuffer);
1136 for (SpvId id : arguments) {
1137 this->writeWord(id, fConstantBuffer);
1138 }
1139 }
1140 return result;
1141}
1142
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001143SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001144 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001145 SkASSERT(c.arguments().size() == 1);
1146 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001147 SkASSERT(constructorType.isFloat());
1148 SkASSERT(argType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001149 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001150 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001151 if (argType.isSigned()) {
1152 this->writeInstruction(SpvOpConvertSToF, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001153 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001154 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001155 SkASSERT(argType.isUnsigned());
1156 this->writeInstruction(SpvOpConvertUToF, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001157 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001158 }
1159 return result;
1160}
1161
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001162SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001163 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001164 SkASSERT(c.arguments().size() == 1);
1165 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001166 SkASSERT(constructorType.isSigned());
1167 SkASSERT(argType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001168 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001169 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001170 if (argType.isFloat()) {
1171 this->writeInstruction(SpvOpConvertFToS, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001172 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001173 }
1174 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001175 SkASSERT(argType.isUnsigned());
1176 this->writeInstruction(SpvOpBitcast, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001177 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001178 }
1179 return result;
1180}
1181
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001182SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001183 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001184 SkASSERT(c.arguments().size() == 1);
1185 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001186 SkASSERT(constructorType.isUnsigned());
1187 SkASSERT(argType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001188 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001189 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001190 if (argType.isFloat()) {
1191 this->writeInstruction(SpvOpConvertFToU, this->getType(constructorType), result, parameter,
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001192 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001193 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001194 SkASSERT(argType.isSigned());
1195 this->writeInstruction(SpvOpBitcast, this->getType(constructorType), result, parameter,
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001196 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001197 }
1198 return result;
1199}
1200
Ethan Nicholas84645e32017-02-09 13:57:14 -05001201void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001202 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001203 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001204 SpvId zeroId = this->writeFloatLiteral(zero);
1205 std::vector<SpvId> columnIds;
1206 for (int column = 0; column < type.columns(); column++) {
1207 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1208 out);
1209 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1210 out);
1211 SpvId columnId = this->nextId();
1212 this->writeWord(columnId, out);
1213 columnIds.push_back(columnId);
1214 for (int row = 0; row < type.columns(); row++) {
1215 this->writeWord(row == column ? diagonal : zeroId, out);
1216 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001217 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001218 }
1219 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1220 out);
1221 this->writeWord(this->getType(type), out);
1222 this->writeWord(id, out);
John Stilesf621e232020-08-25 13:33:02 -04001223 for (SpvId columnId : columnIds) {
1224 this->writeWord(columnId, out);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001225 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001226 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001227}
1228
1229void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001230 const Type& dstType, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001231 SkASSERT(srcType.typeKind() == Type::TypeKind::kMatrix);
1232 SkASSERT(dstType.typeKind() == Type::TypeKind::kMatrix);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001233 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001234 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1235 srcType.rows(),
1236 1));
1237 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1238 dstType.rows(),
1239 1));
1240 SpvId zeroId;
1241 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001242 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001243 zeroId = this->writeFloatLiteral(zero);
1244 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001245 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001246 zeroId = this->writeIntLiteral(zero);
1247 } else {
1248 ABORT("unsupported matrix component type");
1249 }
1250 SpvId zeroColumn = 0;
1251 SpvId columns[4];
1252 for (int i = 0; i < dstType.columns(); i++) {
1253 if (i < srcType.columns()) {
1254 // we're still inside the src matrix, copy the column
1255 SpvId srcColumn = this->nextId();
1256 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001257 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001258 SpvId dstColumn;
1259 if (srcType.rows() == dstType.rows()) {
1260 // columns are equal size, don't need to do anything
1261 dstColumn = srcColumn;
1262 }
1263 else if (dstType.rows() > srcType.rows()) {
1264 // dst column is bigger, need to zero-pad it
1265 dstColumn = this->nextId();
1266 int delta = dstType.rows() - srcType.rows();
1267 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1268 this->writeWord(dstColumnType, out);
1269 this->writeWord(dstColumn, out);
1270 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001271 for (int j = 0; j < delta; ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001272 this->writeWord(zeroId, out);
1273 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001274 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001275 }
1276 else {
1277 // dst column is smaller, need to swizzle the src column
1278 dstColumn = this->nextId();
1279 int count = dstType.rows();
1280 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1281 this->writeWord(dstColumnType, out);
1282 this->writeWord(dstColumn, out);
1283 this->writeWord(srcColumn, out);
1284 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001285 for (int j = 0; j < count; j++) {
1286 this->writeWord(j, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001287 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001288 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001289 }
1290 columns[i] = dstColumn;
1291 } else {
1292 // we're past the end of the src matrix, need a vector of zeroes
1293 if (!zeroColumn) {
1294 zeroColumn = this->nextId();
1295 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1296 this->writeWord(dstColumnType, out);
1297 this->writeWord(zeroColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001298 for (int j = 0; j < dstType.rows(); ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001299 this->writeWord(zeroId, out);
1300 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001301 this->writePrecisionModifier(dstType, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001302 }
1303 columns[i] = zeroColumn;
1304 }
1305 }
1306 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1307 this->writeWord(this->getType(dstType), out);
1308 this->writeWord(id, out);
1309 for (int i = 0; i < dstType.columns(); i++) {
1310 this->writeWord(columns[i], out);
1311 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001312 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001313}
1314
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001315void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1316 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001317 std::vector<SpvId>* columnIds,
1318 int* currentCount, int rows, SpvId entry,
1319 OutputStream& out) {
1320 SkASSERT(*currentCount < rows);
1321 ++(*currentCount);
1322 currentColumn->push_back(entry);
1323 if (*currentCount == rows) {
1324 *currentCount = 0;
1325 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1326 this->writeWord(columnType, out);
1327 SpvId columnId = this->nextId();
1328 this->writeWord(columnId, out);
1329 columnIds->push_back(columnId);
1330 for (SpvId id : *currentColumn) {
1331 this->writeWord(id, out);
1332 }
1333 currentColumn->clear();
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001334 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001335 }
1336}
1337
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001338SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001339 const Type& type = c.type();
1340 SkASSERT(type.typeKind() == Type::TypeKind::kMatrix);
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001341 SkASSERT(c.arguments().size() > 0);
1342 const Type& arg0Type = c.arguments()[0]->type();
ethannicholasb3058bd2016-07-01 08:22:01 -07001343 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1344 // an instruction
1345 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001346 for (size_t i = 0; i < c.arguments().size(); i++) {
1347 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001348 }
1349 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001350 int rows = type.rows();
1351 int columns = type.columns();
1352 if (arguments.size() == 1 && arg0Type.typeKind() == Type::TypeKind::kScalar) {
1353 this->writeUniformScaleMatrix(result, arguments[0], type, out);
1354 } else if (arguments.size() == 1 && arg0Type.typeKind() == Type::TypeKind::kMatrix) {
1355 this->writeMatrixCopy(result, arguments[0], arg0Type, type, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001356 } else if (arguments.size() == 1 &&
Ethan Nicholas30d30222020-09-11 12:27:26 -04001357 arg0Type.typeKind() == Type::TypeKind::kVector) {
1358 SkASSERT(type.rows() == 2 && type.columns() == 2);
1359 SkASSERT(arg0Type.columns() == 4);
1360 SpvId componentType = this->getType(type.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001361 SpvId v[4];
1362 for (int i = 0; i < 4; ++i) {
1363 v[i] = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001364 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i,
1365 out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001366 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001367 SpvId columnType = this->getType(type.componentType().toCompound(fContext, 2, 1));
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001368 SpvId column1 = this->nextId();
1369 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1370 SpvId column2 = this->nextId();
1371 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001372 this->writeInstruction(SpvOpCompositeConstruct, this->getType(type), result, column1,
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001373 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001374 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001375 SpvId columnType = this->getType(type.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001376 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001377 // ids of vectors and scalars we have written to the current column so far
1378 std::vector<SpvId> currentColumn;
1379 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001380 int currentCount = 0;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001381 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001382 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001383 const Type& argType = c.arguments()[i]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001384 if (currentCount == 0 && argType.typeKind() == Type::TypeKind::kVector &&
1385 argType.columns() == type.rows()) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001386 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001387 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001388 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001389 if (argType.columns() == 1) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001390 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1391 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001392 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001393 SpvId componentType = this->getType(argType.componentType());
1394 for (int j = 0; j < argType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001395 SpvId swizzle = this->nextId();
1396 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1397 arguments[i], j, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001398 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1399 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001400 }
1401 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001402 }
1403 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001404 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001405 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001406 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001407 this->writeWord(result, out);
1408 for (SpvId id : columnIds) {
1409 this->writeWord(id, out);
1410 }
1411 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001412 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001413 return result;
1414}
1415
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001416SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001417 const Type& type = c.type();
1418 SkASSERT(type.typeKind() == Type::TypeKind::kVector);
Brian Osmanb6b95732020-06-30 11:44:27 -04001419 if (c.isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001420 return this->writeConstantVector(c);
1421 }
1422 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1423 // an instruction
1424 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001425 for (size_t i = 0; i < c.arguments().size(); i++) {
1426 const Type& argType = c.arguments()[i]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001427 if (argType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001428 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1429 // extract the components and convert them in that case manually. On top of that,
1430 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1431 // doesn't handle vector arguments at all, so we always extract vector components and
1432 // pass them into OpCreateComposite individually.
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001433 SpvId vec = this->writeExpression(*c.arguments()[i], out);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001434 SpvOp_ op = SpvOpUndef;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001435 const Type& src = argType.componentType();
1436 const Type& dst = type.componentType();
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001437 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1438 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001439 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001440 return vec;
1441 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001442 } else if (src == *fContext.fInt_Type ||
1443 src == *fContext.fShort_Type ||
1444 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001445 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001446 } else if (src == *fContext.fUInt_Type ||
1447 src == *fContext.fUShort_Type ||
1448 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001449 op = SpvOpConvertUToF;
1450 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001451 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001452 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001453 } else if (dst == *fContext.fInt_Type ||
1454 dst == *fContext.fShort_Type ||
1455 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001456 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1457 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001458 } else if (src == *fContext.fInt_Type ||
1459 src == *fContext.fShort_Type ||
1460 src == *fContext.fByte_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001461 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001462 return vec;
1463 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001464 } else if (src == *fContext.fUInt_Type ||
1465 src == *fContext.fUShort_Type ||
1466 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001467 op = SpvOpBitcast;
1468 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001469 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001470 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001471 } else if (dst == *fContext.fUInt_Type ||
1472 dst == *fContext.fUShort_Type ||
1473 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001474 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1475 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001476 } else if (src == *fContext.fInt_Type ||
1477 src == *fContext.fShort_Type ||
1478 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001479 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001480 } else if (src == *fContext.fUInt_Type ||
1481 src == *fContext.fUShort_Type ||
1482 src == *fContext.fUByte_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001483 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001484 return vec;
1485 }
1486 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001487 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001488 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001489 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001490 for (int j = 0; j < argType.columns(); j++) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001491 SpvId swizzle = this->nextId();
1492 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1493 out);
1494 if (op != SpvOpUndef) {
1495 SpvId cast = this->nextId();
1496 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1497 arguments.push_back(cast);
1498 } else {
1499 arguments.push_back(swizzle);
1500 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001501 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001502 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001503 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001504 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001505 }
1506 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001507 if (arguments.size() == 1 && c.arguments()[0]->type().typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001508 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(), out);
1509 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001510 this->writeWord(result, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001511 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001512 this->writeWord(arguments[0], out);
1513 }
1514 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001515 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001516 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001517 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001518 this->writeWord(result, out);
1519 for (SpvId id : arguments) {
1520 this->writeWord(id, out);
1521 }
1522 }
1523 return result;
1524}
1525
Ethan Nicholasbd553222017-07-18 15:54:59 -04001526SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001527 const Type& type = c.type();
1528 SkASSERT(type.typeKind() == Type::TypeKind::kArray);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001529 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1530 // an instruction
1531 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001532 for (size_t i = 0; i < c.arguments().size(); i++) {
1533 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholasbd553222017-07-18 15:54:59 -04001534 }
1535 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001536 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.arguments().size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001537 this->writeWord(this->getType(type), out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001538 this->writeWord(result, out);
1539 for (SpvId id : arguments) {
1540 this->writeWord(id, out);
1541 }
1542 return result;
1543}
1544
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001545SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001546 const Type& type = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001547 if (c.arguments().size() == 1 &&
1548 this->getActualType(type) == this->getActualType(c.arguments()[0]->type())) {
1549 return this->writeExpression(*c.arguments()[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001550 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001551 if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001552 return this->writeFloatConstructor(c, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001553 } else if (type == *fContext.fInt_Type ||
1554 type == *fContext.fShort_Type ||
1555 type == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001556 return this->writeIntConstructor(c, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001557 } else if (type == *fContext.fUInt_Type ||
1558 type == *fContext.fUShort_Type ||
1559 type == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001560 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001561 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001562 switch (type.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001563 case Type::TypeKind::kVector:
ethannicholasb3058bd2016-07-01 08:22:01 -07001564 return this->writeVectorConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001565 case Type::TypeKind::kMatrix:
ethannicholasb3058bd2016-07-01 08:22:01 -07001566 return this->writeMatrixConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001567 case Type::TypeKind::kArray:
Ethan Nicholasbd553222017-07-18 15:54:59 -04001568 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001569 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001570#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07001571 ABORT("unsupported constructor: %s", c.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001572#endif
1573 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001574 }
1575}
1576
1577SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1578 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001579 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001580 return SpvStorageClassInput;
1581 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001582 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001583 return SpvStorageClassOutput;
1584 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001585 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001586 return SpvStorageClassPushConstant;
1587 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001588 return SpvStorageClassUniform;
1589 } else {
1590 return SpvStorageClassFunction;
1591 }
1592}
1593
ethannicholasf789b382016-08-03 12:43:36 -07001594SpvStorageClass_ get_storage_class(const Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001595 switch (expr.kind()) {
1596 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -04001597 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001598 if (var.storage() != Variable::Storage::kGlobal) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001599 return SpvStorageClassFunction;
1600 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001601 SpvStorageClass_ result = get_storage_class(var.modifiers());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001602 if (result == SpvStorageClassFunction) {
1603 result = SpvStorageClassPrivate;
1604 }
1605 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001606 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001607 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001608 return get_storage_class(*expr.as<FieldAccess>().base());
Ethan Nicholase6592142020-09-08 10:22:09 -04001609 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001610 return get_storage_class(*expr.as<IndexExpression>().base());
ethannicholasb3058bd2016-07-01 08:22:01 -07001611 default:
1612 return SpvStorageClassFunction;
1613 }
1614}
1615
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001616std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001617 std::vector<SpvId> chain;
Ethan Nicholase6592142020-09-08 10:22:09 -04001618 switch (expr.kind()) {
1619 case Expression::Kind::kIndex: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001620 IndexExpression& indexExpr = (IndexExpression&) expr;
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001621 chain = this->getAccessChain(*indexExpr.base(), out);
1622 chain.push_back(this->writeExpression(*indexExpr.index(), out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001623 break;
1624 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001625 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001626 FieldAccess& fieldExpr = (FieldAccess&) expr;
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001627 chain = this->getAccessChain(*fieldExpr.base(), out);
1628 IntLiteral index(fContext, -1, fieldExpr.fieldIndex());
ethannicholasb3058bd2016-07-01 08:22:01 -07001629 chain.push_back(this->writeIntLiteral(index));
1630 break;
1631 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001632 default: {
1633 SpvId id = this->getLValue(expr, out)->getPointer();
1634 SkASSERT(id != 0);
1635 chain.push_back(id);
1636 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001637 }
1638 return chain;
1639}
1640
1641class PointerLValue : public SPIRVCodeGenerator::LValue {
1642public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001643 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1644 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001645 : fGen(gen)
1646 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001647 , fType(type)
1648 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001649
John Stiles1cf2c8d2020-08-13 22:58:04 -04001650 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001651 return fPointer;
1652 }
1653
John Stiles1cf2c8d2020-08-13 22:58:04 -04001654 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001655 SpvId result = fGen.nextId();
1656 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001657 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001658 return result;
1659 }
1660
John Stiles1cf2c8d2020-08-13 22:58:04 -04001661 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001662 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1663 }
1664
1665private:
1666 SPIRVCodeGenerator& fGen;
1667 const SpvId fPointer;
1668 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001669 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001670};
1671
1672class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1673public:
John Stiles750109b2020-10-30 13:45:46 -04001674 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const ComponentArray& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001675 const Type& baseType, const Type& swizzleType,
1676 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001677 : fGen(gen)
1678 , fVecPointer(vecPointer)
1679 , fComponents(components)
1680 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001681 , fSwizzleType(swizzleType)
1682 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001683
John Stiles1cf2c8d2020-08-13 22:58:04 -04001684 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001685 return 0;
1686 }
1687
John Stiles1cf2c8d2020-08-13 22:58:04 -04001688 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001689 SpvId base = fGen.nextId();
1690 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001691 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001692 SpvId result = fGen.nextId();
1693 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1694 fGen.writeWord(fGen.getType(fSwizzleType), out);
1695 fGen.writeWord(result, out);
1696 fGen.writeWord(base, out);
1697 fGen.writeWord(base, out);
1698 for (int component : fComponents) {
1699 fGen.writeWord(component, out);
1700 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001701 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001702 return result;
1703 }
1704
John Stiles1cf2c8d2020-08-13 22:58:04 -04001705 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001706 // use OpVectorShuffle to mix and match the vector components. We effectively create
1707 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001708 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001709 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001710 // float3L = ...;
1711 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001712 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001713 // 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 -07001714 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1715 // (3, 1, 4).
1716 SpvId base = fGen.nextId();
1717 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1718 SpvId shuffle = fGen.nextId();
1719 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1720 fGen.writeWord(fGen.getType(fBaseType), out);
1721 fGen.writeWord(shuffle, out);
1722 fGen.writeWord(base, out);
1723 fGen.writeWord(value, out);
1724 for (int i = 0; i < fBaseType.columns(); i++) {
1725 // current offset into the virtual vector, defaults to pulling the unmodified
1726 // value from the left side
1727 int offset = i;
1728 // check to see if we are writing this component
1729 for (size_t j = 0; j < fComponents.size(); j++) {
1730 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001731 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001732 // the correct component of the right side instead of preserving the
1733 // value from the left
1734 offset = (int) (j + fBaseType.columns());
1735 break;
1736 }
1737 }
1738 fGen.writeWord(offset, out);
1739 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001740 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001741 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1742 }
1743
1744private:
1745 SPIRVCodeGenerator& fGen;
1746 const SpvId fVecPointer;
John Stiles750109b2020-10-30 13:45:46 -04001747 const ComponentArray& fComponents;
ethannicholasb3058bd2016-07-01 08:22:01 -07001748 const Type& fBaseType;
1749 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001750 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001751};
1752
Greg Daniel64773e62016-11-22 09:44:03 -05001753std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001754 OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001755 const Type& type = expr.type();
1756 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
Ethan Nicholase6592142020-09-08 10:22:09 -04001757 switch (expr.kind()) {
1758 case Expression::Kind::kVariableReference: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001759 SpvId typeId;
Ethan Nicholas78686922020-10-08 06:46:27 -04001760 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001761 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001762 typeId = this->getType(Type("sk_in", Type::TypeKind::kArray,
1763 var.type().componentType(), fSkInCount));
Ethan Nicholas5226b772018-05-03 16:20:41 -04001764 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001765 typeId = this->getType(type);
Ethan Nicholas5226b772018-05-03 16:20:41 -04001766 }
ethannicholasd598f792016-07-25 10:08:54 -07001767 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001768 SkASSERT(entry != fVariableMap.end());
John Stiles5570c512020-11-19 17:58:07 -05001769 return std::make_unique<PointerLValue>(*this, entry->second, typeId, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001770 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001771 case Expression::Kind::kIndex: // fall through
1772 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001773 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1774 SpvId member = this->nextId();
1775 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001776 this->writeWord(this->getPointerType(type, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001777 this->writeWord(member, out);
1778 for (SpvId idx : chain) {
1779 this->writeWord(idx, out);
1780 }
John Stiles5570c512020-11-19 17:58:07 -05001781 return std::make_unique<PointerLValue>(*this, member, this->getType(type), precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001782 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001783 case Expression::Kind::kSwizzle: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001784 Swizzle& swizzle = (Swizzle&) expr;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001785 size_t count = swizzle.components().size();
1786 SpvId base = this->getLValue(*swizzle.base(), out)->getPointer();
John Stiles5570c512020-11-19 17:58:07 -05001787 if (!base) {
1788 fErrors.error(swizzle.fOffset, "unable to retrieve lvalue from swizzle");
1789 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001790 if (count == 1) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001791 IntLiteral index(fContext, -1, swizzle.components()[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001792 SpvId member = this->nextId();
1793 this->writeInstruction(SpvOpAccessChain,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001794 this->getPointerType(type,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001795 get_storage_class(*swizzle.base())),
Greg Daniel64773e62016-11-22 09:44:03 -05001796 member,
1797 base,
1798 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001799 out);
John Stiles5570c512020-11-19 17:58:07 -05001800 return std::make_unique<PointerLValue>(*this, member, this->getType(type),
1801 precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001802 } else {
John Stiles5570c512020-11-19 17:58:07 -05001803 return std::make_unique<SwizzleLValue>(*this, base, swizzle.components(),
1804 swizzle.base()->type(), type, precision);
ethannicholasb3058bd2016-07-01 08:22:01 -07001805 }
1806 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001807 case Expression::Kind::kTernary: {
Ethan Nicholasa583b812018-01-18 13:32:11 -05001808 TernaryExpression& t = (TernaryExpression&) expr;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001809 SpvId test = this->writeExpression(*t.test(), out);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001810 SpvId end = this->nextId();
1811 SpvId ifTrueLabel = this->nextId();
1812 SpvId ifFalseLabel = this->nextId();
1813 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1814 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1815 this->writeLabel(ifTrueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04001816 SpvId ifTrue = this->getLValue(*t.ifTrue(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001817 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001818 this->writeInstruction(SpvOpBranch, end, out);
1819 ifTrueLabel = fCurrentBlock;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001820 SpvId ifFalse = this->getLValue(*t.ifFalse(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001821 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001822 ifFalseLabel = fCurrentBlock;
1823 this->writeInstruction(SpvOpBranch, end, out);
1824 SpvId result = this->nextId();
1825 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1826 ifTrueLabel, ifFalse, ifFalseLabel, out);
John Stiles5570c512020-11-19 17:58:07 -05001827 return std::make_unique<PointerLValue>(*this, result, this->getType(type), precision);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001828 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001829 default: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001830 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001831 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001832 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1833 // caught by IRGenerator
1834 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001835 SpvId pointerType = this->getPointerType(type, SpvStorageClassFunction);
1836 this->writeInstruction(SpvOpVariable, pointerType, result, SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001837 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001838 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
John Stiles5570c512020-11-19 17:58:07 -05001839 return std::make_unique<PointerLValue>(*this, result, this->getType(type), precision);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001840 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001841 }
1842}
1843
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001844SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001845 SpvId result = this->nextId();
Ethan Nicholas78686922020-10-08 06:46:27 -04001846 auto entry = fVariableMap.find(ref.variable());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001847 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001848 SpvId var = entry->second;
Ethan Nicholas78686922020-10-08 06:46:27 -04001849 this->writeInstruction(SpvOpLoad, this->getType(ref.variable()->type()), result, var, out);
1850 this->writePrecisionModifier(ref.variable()->type(), result);
1851 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
Greg Daniela85e4bf2020-06-17 16:32:45 -04001852 (fProgram.fSettings.fFlipY || fProgram.fSettings.fInverseW)) {
1853 // The x component never changes, so just grab it
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001854 SpvId xId = this->nextId();
1855 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1856 result, 0, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001857
1858 // Calculate the y component which may need to be flipped
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001859 SpvId rawYId = this->nextId();
1860 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1861 result, 1, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001862 SpvId flippedYId = 0;
1863 if (fProgram.fSettings.fFlipY) {
1864 // need to remap to a top-left coordinate system
1865 if (fRTHeightStructId == (SpvId)-1) {
1866 // height variable hasn't been written yet
Greg Daniela85e4bf2020-06-17 16:32:45 -04001867 SkASSERT(fRTHeightFieldIndex == (SpvId)-1);
1868 std::vector<Type::Field> fields;
John Stiles5570c512020-11-19 17:58:07 -05001869 if (fProgram.fSettings.fRTHeightOffset < 0) {
1870 fErrors.error(ref.fOffset, "RTHeightOffset is negative");
1871 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001872 fields.emplace_back(
1873 Modifiers(Layout(0, -1, fProgram.fSettings.fRTHeightOffset, -1, -1, -1, -1,
1874 -1, Layout::Format::kUnspecified,
1875 Layout::kUnspecified_Primitive, 1, -1, "", "",
1876 Layout::kNo_Key, Layout::CType::kDefault),
1877 0),
1878 SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1879 StringFragment name("sksl_synthetic_uniforms");
1880 Type intfStruct(-1, name, fields);
1881
1882 int binding = fProgram.fSettings.fRTHeightBinding;
John Stiles5570c512020-11-19 17:58:07 -05001883 if (binding == -1) {
1884 fErrors.error(ref.fOffset, "layout(binding=...) is required in SPIR-V");
1885 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001886 int set = fProgram.fSettings.fRTHeightSet;
John Stiles5570c512020-11-19 17:58:07 -05001887 if (set == -1) {
1888 fErrors.error(ref.fOffset, "layout(set=...) is required in SPIR-V");
1889 }
Greg Daniela85e4bf2020-06-17 16:32:45 -04001890 Layout layout(0, -1, -1, binding, -1, set, -1, -1, Layout::Format::kUnspecified,
1891 Layout::kUnspecified_Primitive, -1, -1, "", "", Layout::kNo_Key,
1892 Layout::CType::kDefault);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001893 Modifiers modifiers(layout, Modifiers::kUniform_Flag);
John Stiles3ae071e2020-08-05 15:29:29 -04001894 const Variable* intfVar = fSynthetics.takeOwnershipOfSymbol(
1895 std::make_unique<Variable>(/*offset=*/-1,
John Stiles586df952020-11-12 18:27:13 -05001896 fProgram.fModifiers->addToPool(modifiers),
John Stiles3ae071e2020-08-05 15:29:29 -04001897 name,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001898 &intfStruct,
Brian Osman3887a012020-09-30 13:22:27 -04001899 /*builtin=*/false,
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001900 Variable::Storage::kGlobal));
John Stiles7c3515b2020-10-16 18:38:39 -04001901 InterfaceBlock intf(/*offset=*/-1, intfVar, name, /*instanceName=*/"",
1902 /*sizes=*/ExpressionArray(),
1903 std::make_shared<SymbolTable>(&fErrors, /*builtin=*/false));
Stephen White88574972020-06-23 19:09:29 -04001904
1905 fRTHeightStructId = this->writeInterfaceBlock(intf, false);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001906 fRTHeightFieldIndex = 0;
Jim Van Verthf3ec9832020-10-21 16:09:57 -04001907 fRTHeightStorageClass = SpvStorageClassUniform;
Greg Daniela85e4bf2020-06-17 16:32:45 -04001908 }
1909 SkASSERT(fRTHeightFieldIndex != (SpvId)-1);
1910
1911 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1912 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1913 SpvId heightPtr = this->nextId();
1914 this->writeOpCode(SpvOpAccessChain, 5, out);
Jim Van Verthf3ec9832020-10-21 16:09:57 -04001915 this->writeWord(this->getPointerType(*fContext.fFloat_Type, fRTHeightStorageClass),
Greg Daniela85e4bf2020-06-17 16:32:45 -04001916 out);
1917 this->writeWord(heightPtr, out);
1918 this->writeWord(fRTHeightStructId, out);
1919 this->writeWord(fieldIndexId, out);
1920 SpvId heightRead = this->nextId();
1921 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1922 heightPtr, out);
1923
1924 flippedYId = this->nextId();
1925 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
1926 heightRead, rawYId, out);
1927 }
1928
1929 // The z component will always be zero so we just get an id to the 0 literal
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001930 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001931 SpvId zeroId = writeFloatLiteral(zero);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001932
1933 // Calculate the w component which may need to be inverted
1934 SpvId rawWId = this->nextId();
1935 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawWId,
Ethan Nicholas20798e52018-12-04 12:30:50 -05001936 result, 3, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001937 SpvId invWId = 0;
1938 if (fProgram.fSettings.fInverseW) {
1939 // We need to invert w
1940 FloatLiteral one(fContext, -1, 1.0);
1941 SpvId oneId = writeFloatLiteral(one);
1942 invWId = this->nextId();
1943 this->writeInstruction(SpvOpFDiv, this->getType(*fContext.fFloat_Type), invWId, oneId,
1944 rawWId, out);
1945 }
1946
1947 // Fill in the new fragcoord with the components from above
1948 SpvId adjusted = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001949 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001950 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001951 this->writeWord(adjusted, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001952 this->writeWord(xId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001953 if (fProgram.fSettings.fFlipY) {
1954 this->writeWord(flippedYId, out);
1955 } else {
1956 this->writeWord(rawYId, out);
1957 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001958 this->writeWord(zeroId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001959 if (fProgram.fSettings.fInverseW) {
1960 this->writeWord(invWId, out);
1961 } else {
1962 this->writeWord(rawWId, out);
1963 }
1964
1965 return adjusted;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001966 }
Ethan Nicholas78686922020-10-08 06:46:27 -04001967 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
Chris Daltonb91c4662018-08-01 10:46:22 -06001968 !fProgram.fSettings.fFlipY) {
1969 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1970 // the default convention of "counter-clockwise face is front".
1971 SpvId inverse = this->nextId();
1972 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1973 result, out);
1974 return inverse;
1975 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001976 return result;
1977}
1978
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001979SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001980 if (expr.base()->type().typeKind() == Type::TypeKind::kVector) {
1981 SpvId base = this->writeExpression(*expr.base(), out);
1982 SpvId index = this->writeExpression(*expr.index(), out);
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001983 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001984 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.type()), result, base,
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001985 index, out);
1986 return result;
1987 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001988 return getLValue(expr, out)->load(out);
1989}
1990
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001991SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001992 return getLValue(f, out)->load(out);
1993}
1994
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001995SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001996 SpvId base = this->writeExpression(*swizzle.base(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001997 SpvId result = this->nextId();
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001998 size_t count = swizzle.components().size();
ethannicholasb3058bd2016-07-01 08:22:01 -07001999 if (count == 1) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002000 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.type()), result, base,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002001 swizzle.components()[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002002 } else {
2003 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002004 this->writeWord(this->getType(swizzle.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002005 this->writeWord(result, out);
2006 this->writeWord(base, out);
Brian Osman25647672020-09-15 15:16:56 -04002007 this->writeWord(base, out);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04002008 for (int component : swizzle.components()) {
Brian Osman25647672020-09-15 15:16:56 -04002009 this->writeWord(component, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002010 }
2011 }
2012 return result;
2013}
2014
Greg Daniel64773e62016-11-22 09:44:03 -05002015SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
2016 const Type& operandType, SpvId lhs,
2017 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002018 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002019 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002020 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002021 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002022 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002023 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002024 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002025 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002026 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002027 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002028 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07002029 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002030#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002031 ABORT("invalid operandType: %s", operandType.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002032#endif
ethannicholasb3058bd2016-07-01 08:22:01 -07002033 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04002034 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002035 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
2036 fDecorationBuffer);
2037 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002038 return result;
2039}
2040
Ethan Nicholas48e24052018-03-14 13:51:39 -04002041SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
2042 OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002043 if (operandType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002044 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04002045 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002046 return result;
2047 }
2048 return id;
2049}
2050
Ethan Nicholas68990be2017-07-13 09:36:52 -04002051SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
2052 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002053 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04002054 OutputStream& out) {
2055 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
Ethan Nicholase6592142020-09-08 10:22:09 -04002056 SkASSERT(operandType.typeKind() == Type::TypeKind::kMatrix);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002057 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2058 operandType.rows(),
2059 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04002060 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002061 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04002062 1));
2063 SpvId boolType = this->getType(*fContext.fBool_Type);
2064 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04002065 for (int i = 0; i < operandType.columns(); i++) {
2066 SpvId columnL = this->nextId();
2067 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2068 SpvId columnR = this->nextId();
2069 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002070 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002071 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
2072 SpvId merge = this->nextId();
2073 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002074 if (result != 0) {
2075 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002076 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002077 result = next;
2078 }
2079 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002080 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04002081 }
2082 }
2083 return result;
2084}
2085
Ethan Nicholas0df21132018-07-10 09:37:51 -04002086SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
2087 SpvId rhs, SpvOp_ floatOperator,
2088 SpvOp_ intOperator,
2089 OutputStream& out) {
2090 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
Ethan Nicholase6592142020-09-08 10:22:09 -04002091 SkASSERT(operandType.typeKind() == Type::TypeKind::kMatrix);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002092 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2093 operandType.rows(),
2094 1));
2095 SpvId columns[4];
2096 for (int i = 0; i < operandType.columns(); i++) {
2097 SpvId columnL = this->nextId();
2098 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2099 SpvId columnR = this->nextId();
2100 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2101 columns[i] = this->nextId();
2102 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2103 }
2104 SpvId result = this->nextId();
2105 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2106 this->writeWord(this->getType(operandType), out);
2107 this->writeWord(result, out);
2108 for (int i = 0; i < operandType.columns(); i++) {
2109 this->writeWord(columns[i], out);
2110 }
2111 return result;
2112}
2113
Ethan Nicholas49465b42019-04-17 12:22:21 -04002114std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2115 if (type.isInteger()) {
2116 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002117 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002118 else if (type.isFloat()) {
2119 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002120 } else {
Ethan Nicholase2c49992020-10-05 11:49:11 -04002121 ABORT("math is unsupported on type '%s'", String(type.name()).c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002122 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002123}
2124
2125SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Token::Kind op,
2126 const Type& rightType, SpvId rhs,
2127 const Type& resultType, OutputStream& out) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002128 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002129 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002130 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2131 // handling in SPIR-V
Ethan Nicholas49465b42019-04-17 12:22:21 -04002132 if (this->getActualType(leftType) != this->getActualType(rightType)) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002133 if (leftType.typeKind() == Type::TypeKind::kVector && rightType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002134 if (op == Token::Kind::TK_SLASH) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002135 SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
2136 SpvId inverse = this->nextId();
2137 this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
2138 rhs = inverse;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002139 op = Token::Kind::TK_STAR;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002140 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002141 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002142 SpvId result = this->nextId();
2143 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2144 result, lhs, rhs, out);
2145 return result;
2146 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002147 // promote number to vector
2148 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002149 const Type& vecType = leftType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002150 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2151 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002152 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002153 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002154 this->writeWord(rhs, out);
2155 }
2156 rhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002157 operandType = &leftType;
Ethan Nicholase6592142020-09-08 10:22:09 -04002158 } else if (rightType.typeKind() == Type::TypeKind::kVector && leftType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002159 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002160 SpvId result = this->nextId();
2161 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2162 result, rhs, lhs, out);
2163 return result;
2164 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002165 // promote number to vector
2166 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002167 const Type& vecType = rightType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002168 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2169 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002170 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002171 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002172 this->writeWord(lhs, out);
2173 }
2174 lhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002175 operandType = &rightType;
Ethan Nicholase6592142020-09-08 10:22:09 -04002176 } else if (leftType.typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002177 SpvOp_ spvop;
Ethan Nicholase6592142020-09-08 10:22:09 -04002178 if (rightType.typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002179 spvop = SpvOpMatrixTimesMatrix;
Ethan Nicholase6592142020-09-08 10:22:09 -04002180 } else if (rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002181 spvop = SpvOpMatrixTimesVector;
ethannicholasb3058bd2016-07-01 08:22:01 -07002182 } else {
Ethan Nicholase6592142020-09-08 10:22:09 -04002183 SkASSERT(rightType.typeKind() == Type::TypeKind::kScalar);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002184 spvop = SpvOpMatrixTimesScalar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002185 }
2186 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002187 this->writeInstruction(spvop, this->getType(resultType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002188 return result;
Ethan Nicholase6592142020-09-08 10:22:09 -04002189 } else if (rightType.typeKind() == Type::TypeKind::kMatrix) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002190 SpvId result = this->nextId();
Ethan Nicholase6592142020-09-08 10:22:09 -04002191 if (leftType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002192 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(resultType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002193 lhs, rhs, out);
2194 } else {
Ethan Nicholase6592142020-09-08 10:22:09 -04002195 SkASSERT(leftType.typeKind() == Type::TypeKind::kScalar);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002196 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(resultType), result,
2197 rhs, lhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002198 }
2199 return result;
2200 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002201 SkASSERT(false);
2202 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002203 }
2204 } else {
John Stiles2d4f9592020-10-30 10:29:12 -04002205 operandType = &this->getActualType(leftType);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002206 SkASSERT(*operandType == this->getActualType(rightType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002207 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002208 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002209 case Token::Kind::TK_EQEQ: {
Ethan Nicholase6592142020-09-08 10:22:09 -04002210 if (operandType->typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002211 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002212 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002213 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002214 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002215 const Type* tmpType;
Ethan Nicholase6592142020-09-08 10:22:09 -04002216 if (operandType->typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002217 tmpType = &fContext.fBool_Type->toCompound(fContext,
2218 operandType->columns(),
2219 operandType->rows());
2220 } else {
2221 tmpType = &resultType;
2222 }
2223 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002224 SpvOpFOrdEqual, SpvOpIEqual,
2225 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002226 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002227 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002228 case Token::Kind::TK_NEQ:
Ethan Nicholase6592142020-09-08 10:22:09 -04002229 if (operandType->typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002230 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002231 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002232 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002233 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002234 const Type* tmpType;
Ethan Nicholase6592142020-09-08 10:22:09 -04002235 if (operandType->typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002236 tmpType = &fContext.fBool_Type->toCompound(fContext,
2237 operandType->columns(),
2238 operandType->rows());
2239 } else {
2240 tmpType = &resultType;
2241 }
2242 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002243 SpvOpFOrdNotEqual, SpvOpINotEqual,
2244 SpvOpINotEqual, SpvOpLogicalNotEqual,
2245 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002246 *operandType, SpvOpAny, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002247 case Token::Kind::TK_GT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002248 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002249 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2250 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002251 SpvOpUGreaterThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002252 case Token::Kind::TK_LT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002253 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002254 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002255 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002256 case Token::Kind::TK_GTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002257 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002258 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2259 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002260 SpvOpUGreaterThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002261 case Token::Kind::TK_LTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002262 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002263 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2264 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002265 SpvOpULessThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002266 case Token::Kind::TK_PLUS:
Ethan Nicholase6592142020-09-08 10:22:09 -04002267 if (leftType.typeKind() == Type::TypeKind::kMatrix &&
2268 rightType.typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002269 SkASSERT(leftType == rightType);
2270 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002271 SpvOpFAdd, SpvOpIAdd, out);
2272 }
Greg Daniel64773e62016-11-22 09:44:03 -05002273 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002274 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002275 case Token::Kind::TK_MINUS:
Ethan Nicholase6592142020-09-08 10:22:09 -04002276 if (leftType.typeKind() == Type::TypeKind::kMatrix &&
2277 rightType.typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002278 SkASSERT(leftType == rightType);
2279 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002280 SpvOpFSub, SpvOpISub, out);
2281 }
Greg Daniel64773e62016-11-22 09:44:03 -05002282 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002283 SpvOpISub, SpvOpISub, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002284 case Token::Kind::TK_STAR:
Ethan Nicholase6592142020-09-08 10:22:09 -04002285 if (leftType.typeKind() == Type::TypeKind::kMatrix &&
2286 rightType.typeKind() == Type::TypeKind::kMatrix) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002287 // matrix multiply
2288 SpvId result = this->nextId();
2289 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2290 lhs, rhs, out);
2291 return result;
2292 }
Greg Daniel64773e62016-11-22 09:44:03 -05002293 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002294 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002295 case Token::Kind::TK_SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002296 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002297 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002298 case Token::Kind::TK_PERCENT:
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002299 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2300 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002301 case Token::Kind::TK_SHL:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002302 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2303 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2304 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002305 case Token::Kind::TK_SHR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002306 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2307 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2308 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002309 case Token::Kind::TK_BITWISEAND:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002310 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2311 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002312 case Token::Kind::TK_BITWISEOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002313 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2314 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002315 case Token::Kind::TK_BITWISEXOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002316 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2317 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002318 case Token::Kind::TK_COMMA:
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04002319 return rhs;
ethannicholasb3058bd2016-07-01 08:22:01 -07002320 default:
John Stiles5570c512020-11-19 17:58:07 -05002321 fErrors.error(0, "unsupported token");
Ethan Nicholas49465b42019-04-17 12:22:21 -04002322 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002323 }
2324}
2325
Ethan Nicholas49465b42019-04-17 12:22:21 -04002326SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
John Stiles2d4f9592020-10-30 10:29:12 -04002327 const Expression& left = *b.left();
2328 const Expression& right = *b.right();
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002329 Token::Kind op = b.getOperator();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002330 // handle cases where we don't necessarily evaluate both LHS and RHS
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002331 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002332 case Token::Kind::TK_EQ: {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002333 SpvId rhs = this->writeExpression(right, out);
2334 this->getLValue(left, out)->store(rhs, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002335 return rhs;
2336 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002337 case Token::Kind::TK_LOGICALAND:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002338 return this->writeLogicalAnd(b, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002339 case Token::Kind::TK_LOGICALOR:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002340 return this->writeLogicalOr(b, out);
2341 default:
2342 break;
2343 }
2344
2345 std::unique_ptr<LValue> lvalue;
2346 SpvId lhs;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002347 if (Compiler::IsAssignment(op)) {
2348 lvalue = this->getLValue(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002349 lhs = lvalue->load(out);
2350 } else {
2351 lvalue = nullptr;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002352 lhs = this->writeExpression(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002353 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002354 SpvId rhs = this->writeExpression(right, out);
2355 SpvId result = this->writeBinaryExpression(left.type(), lhs, Compiler::RemoveAssignment(op),
2356 right.type(), rhs, b.type(), out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002357 if (lvalue) {
2358 lvalue->store(result, out);
2359 }
2360 return result;
2361}
2362
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002363SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002364 SkASSERT(a.getOperator() == Token::Kind::TK_LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002365 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002366 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
John Stiles2d4f9592020-10-30 10:29:12 -04002367 SpvId lhs = this->writeExpression(*a.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002368 SpvId rhsLabel = this->nextId();
2369 SpvId end = this->nextId();
2370 SpvId lhsBlock = fCurrentBlock;
2371 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2372 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2373 this->writeLabel(rhsLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04002374 SpvId rhs = this->writeExpression(*a.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002375 SpvId rhsBlock = fCurrentBlock;
2376 this->writeInstruction(SpvOpBranch, end, out);
2377 this->writeLabel(end, out);
2378 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002379 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002380 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002381 return result;
2382}
2383
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002384SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002385 SkASSERT(o.getOperator() == Token::Kind::TK_LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002386 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002387 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
John Stiles2d4f9592020-10-30 10:29:12 -04002388 SpvId lhs = this->writeExpression(*o.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002389 SpvId rhsLabel = this->nextId();
2390 SpvId end = this->nextId();
2391 SpvId lhsBlock = fCurrentBlock;
2392 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2393 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2394 this->writeLabel(rhsLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04002395 SpvId rhs = this->writeExpression(*o.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002396 SpvId rhsBlock = fCurrentBlock;
2397 this->writeInstruction(SpvOpBranch, end, out);
2398 this->writeLabel(end, out);
2399 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002400 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002401 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002402 return result;
2403}
2404
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002405SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002406 const Type& type = t.type();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002407 SpvId test = this->writeExpression(*t.test(), out);
2408 if (t.ifTrue()->type().columns() == 1 &&
2409 t.ifTrue()->isCompileTimeConstant() &&
2410 t.ifFalse()->isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002411 // both true and false are constants, can just use OpSelect
2412 SpvId result = this->nextId();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002413 SpvId trueId = this->writeExpression(*t.ifTrue(), out);
2414 SpvId falseId = this->writeExpression(*t.ifFalse(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002415 this->writeInstruction(SpvOpSelect, this->getType(type), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002416 out);
2417 return result;
2418 }
Greg Daniel64773e62016-11-22 09:44:03 -05002419 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002420 // Adreno. Switched to storing the result in a temp variable as glslang does.
2421 SpvId var = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002422 this->writeInstruction(SpvOpVariable, this->getPointerType(type, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002423 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002424 SpvId trueLabel = this->nextId();
2425 SpvId falseLabel = this->nextId();
2426 SpvId end = this->nextId();
2427 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2428 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2429 this->writeLabel(trueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002430 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifTrue(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002431 this->writeInstruction(SpvOpBranch, end, out);
2432 this->writeLabel(falseLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002433 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifFalse(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002434 this->writeInstruction(SpvOpBranch, end, out);
2435 this->writeLabel(end, out);
2436 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002437 this->writeInstruction(SpvOpLoad, this->getType(type), result, var, out);
2438 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002439 return result;
2440}
2441
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002442SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002443 const Type& type = p.type();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002444 if (p.getOperator() == Token::Kind::TK_MINUS) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002445 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002446 SpvId typeId = this->getType(type);
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002447 SpvId expr = this->writeExpression(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002448 if (is_float(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002449 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002450 } else if (is_signed(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002451 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2452 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002453#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002454 ABORT("unsupported prefix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002455#endif
Brian Salomon23356442018-11-30 15:33:19 -05002456 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002457 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002458 return result;
2459 }
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002460 switch (p.getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002461 case Token::Kind::TK_PLUS:
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002462 return this->writeExpression(*p.operand(), out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002463 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002464 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002465 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
2466 SpvId result = this->writeBinaryOperation(type, type, lv->load(out), one,
Greg Daniel64773e62016-11-22 09:44:03 -05002467 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002468 out);
2469 lv->store(result, out);
2470 return result;
2471 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002472 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002473 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002474 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
2475 SpvId result = this->writeBinaryOperation(type, type, lv->load(out), one, SpvOpFSub,
2476 SpvOpISub, SpvOpISub, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002477 lv->store(result, out);
2478 return result;
2479 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002480 case Token::Kind::TK_LOGICALNOT: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002481 SkASSERT(p.operand()->type() == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002482 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002483 this->writeInstruction(SpvOpLogicalNot, this->getType(type), result,
2484 this->writeExpression(*p.operand(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002485 return result;
2486 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002487 case Token::Kind::TK_BITWISENOT: {
ethannicholas5961bc92016-10-12 06:39:56 -07002488 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002489 this->writeInstruction(SpvOpNot, this->getType(type), result,
2490 this->writeExpression(*p.operand(), out), out);
ethannicholas5961bc92016-10-12 06:39:56 -07002491 return result;
2492 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002493 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002494#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002495 ABORT("unsupported prefix expression: %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002496#endif
2497 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002498 }
2499}
2500
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002501SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002502 const Type& type = p.type();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002503 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002504 SpvId result = lv->load(out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002505 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002506 switch (p.getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002507 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002508 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002509 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2510 lv->store(temp, out);
2511 return result;
2512 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002513 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002514 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002515 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2516 lv->store(temp, out);
2517 return result;
2518 }
2519 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002520#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002521 ABORT("unsupported postfix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002522#endif
2523 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002524 }
2525}
2526
ethannicholasf789b382016-08-03 12:43:36 -07002527SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
Ethan Nicholas59d660c2020-09-28 09:18:15 -04002528 if (b.value()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002529 if (fBoolTrue == 0) {
2530 fBoolTrue = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002531 this->writeInstruction(SpvOpConstantTrue, this->getType(b.type()), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002532 fConstantBuffer);
2533 }
2534 return fBoolTrue;
2535 } else {
2536 if (fBoolFalse == 0) {
2537 fBoolFalse = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002538 this->writeInstruction(SpvOpConstantFalse, this->getType(b.type()), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002539 fConstantBuffer);
2540 }
2541 return fBoolFalse;
2542 }
2543}
2544
ethannicholasf789b382016-08-03 12:43:36 -07002545SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002546 const Type& type = i.type();
2547 ConstantType constantType;
2548 if (type == *fContext.fInt_Type) {
2549 constantType = ConstantType::kInt;
2550 } else if (type == *fContext.fUInt_Type) {
2551 constantType = ConstantType::kUInt;
2552 } else if (type == *fContext.fShort_Type || type == *fContext.fByte_Type) {
2553 constantType = ConstantType::kShort;
2554 } else if (type == *fContext.fUShort_Type || type == *fContext.fUByte_Type) {
2555 constantType = ConstantType::kUShort;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002556 } else {
2557 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002558 }
Ethan Nicholase96cdd12020-09-28 16:27:18 -04002559 std::pair<ConstantValue, ConstantType> key(i.value(), constantType);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002560 auto entry = fNumberConstants.find(key);
2561 if (entry == fNumberConstants.end()) {
2562 SpvId result = this->nextId();
Ethan Nicholase96cdd12020-09-28 16:27:18 -04002563 this->writeInstruction(SpvOpConstant, this->getType(type), result, (SpvId) i.value(),
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002564 fConstantBuffer);
2565 fNumberConstants[key] = result;
2566 return result;
2567 }
2568 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002569}
2570
ethannicholasf789b382016-08-03 12:43:36 -07002571SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002572 const Type& type = f.type();
2573 ConstantType constantType;
2574 if (type == *fContext.fHalf_Type) {
2575 constantType = ConstantType::kHalf;
ethannicholasb3058bd2016-07-01 08:22:01 -07002576 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002577 constantType = ConstantType::kFloat;
ethannicholasb3058bd2016-07-01 08:22:01 -07002578 }
Ethan Nicholasa3f22f12020-10-01 12:13:17 -04002579 float value = (float) f.value();
2580 std::pair<ConstantValue, ConstantType> key(f.value(), constantType);
John Stiles8c578662020-06-01 15:32:47 +00002581 auto entry = fNumberConstants.find(key);
2582 if (entry == fNumberConstants.end()) {
2583 SpvId result = this->nextId();
2584 uint32_t bits;
2585 SkASSERT(sizeof(bits) == sizeof(value));
2586 memcpy(&bits, &value, sizeof(bits));
Ethan Nicholas30d30222020-09-11 12:27:26 -04002587 this->writeInstruction(SpvOpConstant, this->getType(type), result, bits,
John Stiles8c578662020-06-01 15:32:47 +00002588 fConstantBuffer);
2589 fNumberConstants[key] = result;
2590 return result;
2591 }
2592 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002593}
2594
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002595SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002596 SpvId result = fFunctionMap[&f];
Ethan Nicholased84b732020-10-08 11:45:44 -04002597 this->writeInstruction(SpvOpFunction, this->getType(f.returnType()), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002598 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04002599 this->writeInstruction(SpvOpName, result, f.name(), fNameBuffer);
Brian Osman5bf3e202020-10-13 10:34:18 -04002600 const std::vector<const Variable*>& parameters = f.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -04002601 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002602 SpvId id = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -04002603 fVariableMap[parameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002604 SpvId type;
Ethan Nicholased84b732020-10-08 11:45:44 -04002605 type = this->getPointerType(parameters[i]->type(), SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002606 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2607 }
2608 return result;
2609}
2610
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002611SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2612 fVariableBuffer.reset();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002613 SpvId result = this->writeFunctionStart(f.declaration(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002614 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002615 StringStream bodyBuffer;
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002616 this->writeBlock((Block&) *f.body(), bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002617 write_stringstream(fVariableBuffer, out);
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002618 if (f.declaration().name() == "main") {
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002619 write_stringstream(fGlobalInitializersBuffer, out);
2620 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002621 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002622 if (fCurrentBlock) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002623 if (f.declaration().returnType() == *fContext.fVoid_Type) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002624 this->writeInstruction(SpvOpReturn, out);
2625 } else {
2626 this->writeInstruction(SpvOpUnreachable, out);
2627 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002628 }
2629 this->writeInstruction(SpvOpFunctionEnd, out);
2630 return result;
2631}
2632
2633void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2634 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002635 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002636 fDecorationBuffer);
2637 }
2638 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002639 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002640 fDecorationBuffer);
2641 }
2642 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002643 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002644 fDecorationBuffer);
2645 }
2646 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002647 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002648 fDecorationBuffer);
2649 }
Greg Daniel64773e62016-11-22 09:44:03 -05002650 if (layout.fInputAttachmentIndex >= 0) {
2651 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2652 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002653 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002654 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002655 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002656 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002657 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002658 fDecorationBuffer);
2659 }
2660}
2661
2662void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2663 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002664 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002665 layout.fLocation, fDecorationBuffer);
2666 }
2667 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002668 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002669 layout.fBinding, fDecorationBuffer);
2670 }
2671 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002672 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002673 layout.fIndex, fDecorationBuffer);
2674 }
2675 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002676 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002677 layout.fSet, fDecorationBuffer);
2678 }
Greg Daniel64773e62016-11-22 09:44:03 -05002679 if (layout.fInputAttachmentIndex >= 0) {
2680 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2681 layout.fInputAttachmentIndex, fDecorationBuffer);
2682 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002683 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002684 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002685 layout.fBuiltin, fDecorationBuffer);
2686 }
2687}
2688
Ethan Nicholas81d15112018-07-13 12:48:50 -04002689static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2690 switch (m.fLayout.fPrimitive) {
2691 case Layout::kPoints_Primitive:
2692 *outSkInCount = 1;
2693 break;
2694 case Layout::kLines_Primitive:
2695 *outSkInCount = 2;
2696 break;
2697 case Layout::kLinesAdjacency_Primitive:
2698 *outSkInCount = 4;
2699 break;
2700 case Layout::kTriangles_Primitive:
2701 *outSkInCount = 3;
2702 break;
2703 case Layout::kTrianglesAdjacency_Primitive:
2704 *outSkInCount = 6;
2705 break;
2706 default:
2707 return;
2708 }
2709}
2710
Stephen White88574972020-06-23 19:09:29 -04002711SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf, bool appendRTHeight) {
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002712 bool isBuffer = ((intf.variable().modifiers().fFlags & Modifiers::kBuffer_Flag) != 0);
2713 bool pushConstant = ((intf.variable().modifiers().fLayout.fFlags &
2714 Layout::kPushConstant_Flag) != 0);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002715 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2716 MemoryLayout(MemoryLayout::k430_Standard) :
2717 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002718 SpvId result = this->nextId();
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002719 const Type* type = &intf.variable().type();
John Stiles0023c0c2020-11-16 13:32:18 -05002720 if (!memoryLayout.layoutIsSupported(*type)) {
2721 fErrors.error(type->fOffset, "type '" + type->name() + "' is not permitted here");
2722 return this->nextId();
2723 }
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002724 Modifiers intfModifiers = intf.variable().modifiers();
2725 SpvStorageClass_ storageClass = get_storage_class(intfModifiers);
Stephen White88574972020-06-23 19:09:29 -04002726 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Greg Daniele6ab9982018-08-22 13:56:32 +00002727 SkASSERT(fRTHeightStructId == (SpvId) -1);
2728 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002729 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002730 fRTHeightStructId = result;
2731 fRTHeightFieldIndex = fields.size();
Jim Van Verthf3ec9832020-10-21 16:09:57 -04002732 fRTHeightStorageClass = storageClass;
Greg Daniele6ab9982018-08-22 13:56:32 +00002733 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002734 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002735 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002736 SpvId typeId;
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002737 if (intfModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osman133724c2020-10-28 14:14:39 -04002738 for (const ProgramElement* e : fProgram.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04002739 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04002740 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholas81d15112018-07-13 12:48:50 -04002741 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002742 }
2743 }
Ethan Nicholase6592142020-09-08 10:22:09 -04002744 typeId = this->getType(Type("sk_in", Type::TypeKind::kArray,
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002745 intf.variable().type().componentType(),
Ethan Nicholase6592142020-09-08 10:22:09 -04002746 fSkInCount),
2747 memoryLayout);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002748 } else {
2749 typeId = this->getType(*type, memoryLayout);
2750 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002751 if (intfModifiers.fFlags & Modifiers::kBuffer_Flag) {
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002752 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002753 } else if (intfModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002754 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002755 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002756 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002757 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002758 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002759 Layout layout = intfModifiers.fLayout;
2760 if (intfModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002761 layout.fSet = 0;
2762 }
2763 this->writeLayout(layout, result);
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002764 fVariableMap[&intf.variable()] = result;
Stephen White88574972020-06-23 19:09:29 -04002765 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002766 delete type;
2767 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002768 return result;
2769}
2770
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002771void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002772 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2773}
2774
2775void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2776 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002777 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2778 }
2779}
2780
Brian Osman010ce6a2020-10-19 16:34:10 -04002781bool is_dead(const Variable& var, const ProgramUsage* usage) {
2782 ProgramUsage::VariableCounts counts = usage->get(var);
2783 if (counts.fRead || counts.fWrite) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002784 return false;
2785 }
2786 // not entirely sure what the rules are for when it's safe to elide interface variables, but it
2787 // causes various problems to elide some of them even when dead. But it also causes problems
2788 // *not* to elide sk_SampleMask when it's not being used.
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002789 if (!(var.modifiers().fFlags & (Modifiers::kIn_Flag |
2790 Modifiers::kOut_Flag |
2791 Modifiers::kUniform_Flag |
2792 Modifiers::kBuffer_Flag))) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002793 return true;
2794 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002795 return var.modifiers().fLayout.fBuiltin == SK_SAMPLEMASK_BUILTIN;
Chris Dalton2284aab2019-11-15 11:02:24 -07002796}
2797
ethannicholas5961bc92016-10-12 06:39:56 -07002798#define BUILTIN_IGNORE 9999
Brian Osmanc0213602020-10-06 14:43:32 -04002799void SPIRVCodeGenerator::writeGlobalVar(Program::Kind kind, const VarDeclaration& varDecl,
2800 OutputStream& out) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002801 const Variable& var = varDecl.var();
Brian Osmanc0213602020-10-06 14:43:32 -04002802 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2803 // in the OpenGL backend.
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002804 SkASSERT(!(var.modifiers().fFlags & (Modifiers::kReadOnly_Flag |
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002805 Modifiers::kWriteOnly_Flag |
2806 Modifiers::kCoherent_Flag |
2807 Modifiers::kVolatile_Flag |
2808 Modifiers::kRestrict_Flag)));
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002809 if (var.modifiers().fLayout.fBuiltin == BUILTIN_IGNORE) {
Brian Osmanc0213602020-10-06 14:43:32 -04002810 return;
2811 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002812 if (var.modifiers().fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
Brian Osmanc0213602020-10-06 14:43:32 -04002813 kind != Program::kFragment_Kind) {
2814 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
2815 return;
2816 }
Brian Osman010ce6a2020-10-19 16:34:10 -04002817 if (is_dead(var, fProgram.fUsage.get())) {
Brian Osmanc0213602020-10-06 14:43:32 -04002818 return;
2819 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002820 const Type& type = var.type();
Brian Osmanc0213602020-10-06 14:43:32 -04002821 SpvStorageClass_ storageClass;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002822 if (var.modifiers().fFlags & Modifiers::kIn_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002823 storageClass = SpvStorageClassInput;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002824 } else if (var.modifiers().fFlags & Modifiers::kOut_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002825 storageClass = SpvStorageClassOutput;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002826 } else if (var.modifiers().fFlags & Modifiers::kUniform_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002827 if (type.typeKind() == Type::TypeKind::kSampler ||
2828 type.typeKind() == Type::TypeKind::kSeparateSampler ||
2829 type.typeKind() == Type::TypeKind::kTexture) {
2830 storageClass = SpvStorageClassUniformConstant;
ethannicholasb3058bd2016-07-01 08:22:01 -07002831 } else {
Brian Osmanc0213602020-10-06 14:43:32 -04002832 storageClass = SpvStorageClassUniform;
ethannicholasb3058bd2016-07-01 08:22:01 -07002833 }
Brian Osmanc0213602020-10-06 14:43:32 -04002834 } else {
2835 storageClass = SpvStorageClassPrivate;
2836 }
2837 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002838 fVariableMap[&var] = id;
Brian Osmanc0213602020-10-06 14:43:32 -04002839 SpvId typeId;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002840 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osmanc0213602020-10-06 14:43:32 -04002841 typeId = this->getPointerType(
2842 Type("sk_in", Type::TypeKind::kArray, type.componentType(), fSkInCount),
2843 storageClass);
2844 } else {
2845 typeId = this->getPointerType(type, storageClass);
2846 }
2847 this->writeInstruction(SpvOpVariable, typeId, id, storageClass, fConstantBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002848 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002849 this->writePrecisionModifier(type, id);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002850 if (varDecl.value()) {
Brian Osmanc0213602020-10-06 14:43:32 -04002851 SkASSERT(!fCurrentBlock);
2852 fCurrentBlock = -1;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002853 SpvId value = this->writeExpression(*varDecl.value(), fGlobalInitializersBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002854 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
2855 fCurrentBlock = 0;
2856 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002857 this->writeLayout(var.modifiers().fLayout, id);
2858 if (var.modifiers().fFlags & Modifiers::kFlat_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002859 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2860 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002861 if (var.modifiers().fFlags & Modifiers::kNoPerspective_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002862 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2863 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002864 }
2865}
2866
Brian Osmanc0213602020-10-06 14:43:32 -04002867void SPIRVCodeGenerator::writeVarDeclaration(const VarDeclaration& varDecl, OutputStream& out) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002868 const Variable& var = varDecl.var();
Brian Osmanc0213602020-10-06 14:43:32 -04002869 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2870 // in the OpenGL backend.
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002871 SkASSERT(!(var.modifiers().fFlags & (Modifiers::kReadOnly_Flag |
2872 Modifiers::kWriteOnly_Flag |
2873 Modifiers::kCoherent_Flag |
2874 Modifiers::kVolatile_Flag |
2875 Modifiers::kRestrict_Flag)));
Brian Osmanc0213602020-10-06 14:43:32 -04002876 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002877 fVariableMap[&var] = id;
2878 SpvId type = this->getPointerType(var.type(), SpvStorageClassFunction);
Brian Osmanc0213602020-10-06 14:43:32 -04002879 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002880 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
2881 if (varDecl.value()) {
2882 SpvId value = this->writeExpression(*varDecl.value(), out);
Brian Osmanc0213602020-10-06 14:43:32 -04002883 this->writeInstruction(SpvOpStore, id, value, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002884 }
2885}
2886
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002887void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002888 switch (s.kind()) {
John Stiles98c1f822020-09-09 14:18:53 -04002889 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04002890 case Statement::Kind::kNop:
Ethan Nicholascb670962017-04-20 19:31:52 -04002891 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002892 case Statement::Kind::kBlock:
ethannicholasb3058bd2016-07-01 08:22:01 -07002893 this->writeBlock((Block&) s, out);
2894 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002895 case Statement::Kind::kExpression:
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04002896 this->writeExpression(*s.as<ExpressionStatement>().expression(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002897 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002898 case Statement::Kind::kReturn:
John Stiles26f98502020-08-18 09:30:51 -04002899 this->writeReturnStatement(s.as<ReturnStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002900 break;
Brian Osmanc0213602020-10-06 14:43:32 -04002901 case Statement::Kind::kVarDeclaration:
2902 this->writeVarDeclaration(s.as<VarDeclaration>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002903 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002904 case Statement::Kind::kIf:
John Stiles26f98502020-08-18 09:30:51 -04002905 this->writeIfStatement(s.as<IfStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002906 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002907 case Statement::Kind::kFor:
John Stiles26f98502020-08-18 09:30:51 -04002908 this->writeForStatement(s.as<ForStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002909 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002910 case Statement::Kind::kWhile:
John Stiles26f98502020-08-18 09:30:51 -04002911 this->writeWhileStatement(s.as<WhileStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002912 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002913 case Statement::Kind::kDo:
John Stiles26f98502020-08-18 09:30:51 -04002914 this->writeDoStatement(s.as<DoStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002915 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002916 case Statement::Kind::kSwitch:
John Stiles26f98502020-08-18 09:30:51 -04002917 this->writeSwitchStatement(s.as<SwitchStatement>(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002918 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002919 case Statement::Kind::kBreak:
ethannicholasb3058bd2016-07-01 08:22:01 -07002920 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2921 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002922 case Statement::Kind::kContinue:
ethannicholasb3058bd2016-07-01 08:22:01 -07002923 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2924 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002925 case Statement::Kind::kDiscard:
ethannicholasb3058bd2016-07-01 08:22:01 -07002926 this->writeInstruction(SpvOpKill, out);
2927 break;
2928 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002929#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002930 ABORT("unsupported statement: %s", s.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002931#endif
2932 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002933 }
2934}
2935
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002936void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04002937 for (const std::unique_ptr<Statement>& stmt : b.children()) {
2938 this->writeStatement(*stmt, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002939 }
2940}
2941
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002942void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002943 SpvId test = this->writeExpression(*stmt.test(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002944 SpvId ifTrue = this->nextId();
2945 SpvId ifFalse = this->nextId();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002946 if (stmt.ifFalse()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002947 SpvId end = this->nextId();
2948 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2949 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2950 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002951 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002952 if (fCurrentBlock) {
2953 this->writeInstruction(SpvOpBranch, end, out);
2954 }
2955 this->writeLabel(ifFalse, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002956 this->writeStatement(*stmt.ifFalse(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002957 if (fCurrentBlock) {
2958 this->writeInstruction(SpvOpBranch, end, out);
2959 }
2960 this->writeLabel(end, out);
2961 } else {
2962 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2963 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2964 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002965 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002966 if (fCurrentBlock) {
2967 this->writeInstruction(SpvOpBranch, ifFalse, out);
2968 }
2969 this->writeLabel(ifFalse, out);
2970 }
2971}
2972
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002973void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04002974 if (f.initializer()) {
2975 this->writeStatement(*f.initializer(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002976 }
2977 SpvId header = this->nextId();
2978 SpvId start = this->nextId();
2979 SpvId body = this->nextId();
2980 SpvId next = this->nextId();
2981 fContinueTarget.push(next);
2982 SpvId end = this->nextId();
2983 fBreakTarget.push(end);
2984 this->writeInstruction(SpvOpBranch, header, out);
2985 this->writeLabel(header, out);
2986 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002987 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002988 this->writeLabel(start, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04002989 if (f.test()) {
2990 SpvId test = this->writeExpression(*f.test(), out);
ethannicholas22f939e2016-10-13 13:25:34 -07002991 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2992 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002993 this->writeLabel(body, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04002994 this->writeStatement(*f.statement(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002995 if (fCurrentBlock) {
2996 this->writeInstruction(SpvOpBranch, next, out);
2997 }
2998 this->writeLabel(next, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04002999 if (f.next()) {
3000 this->writeExpression(*f.next(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003001 }
3002 this->writeInstruction(SpvOpBranch, header, out);
3003 this->writeLabel(end, out);
3004 fBreakTarget.pop();
3005 fContinueTarget.pop();
3006}
3007
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003008void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003009 SpvId header = this->nextId();
3010 SpvId start = this->nextId();
3011 SpvId body = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003012 SpvId continueTarget = this->nextId();
3013 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003014 SpvId end = this->nextId();
3015 fBreakTarget.push(end);
3016 this->writeInstruction(SpvOpBranch, header, out);
3017 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003018 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003019 this->writeInstruction(SpvOpBranch, start, out);
3020 this->writeLabel(start, out);
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003021 SpvId test = this->writeExpression(*w.test(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003022 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
3023 this->writeLabel(body, out);
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003024 this->writeStatement(*w.statement(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003025 if (fCurrentBlock) {
Ethan Nicholas0d997662019-04-08 09:46:01 -04003026 this->writeInstruction(SpvOpBranch, continueTarget, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003027 }
Ethan Nicholas0d997662019-04-08 09:46:01 -04003028 this->writeLabel(continueTarget, out);
3029 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003030 this->writeLabel(end, out);
3031 fBreakTarget.pop();
3032 fContinueTarget.pop();
3033}
3034
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003035void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003036 SpvId header = this->nextId();
3037 SpvId start = this->nextId();
3038 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003039 SpvId continueTarget = this->nextId();
3040 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003041 SpvId end = this->nextId();
3042 fBreakTarget.push(end);
3043 this->writeInstruction(SpvOpBranch, header, out);
3044 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003045 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003046 this->writeInstruction(SpvOpBranch, start, out);
3047 this->writeLabel(start, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003048 this->writeStatement(*d.statement(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003049 if (fCurrentBlock) {
3050 this->writeInstruction(SpvOpBranch, next, out);
3051 }
3052 this->writeLabel(next, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003053 SpvId test = this->writeExpression(*d.test(), out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003054 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
3055 this->writeLabel(continueTarget, out);
3056 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003057 this->writeLabel(end, out);
3058 fBreakTarget.pop();
3059 fContinueTarget.pop();
3060}
3061
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003062void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
Ethan Nicholas01b05e52020-10-22 15:53:41 -04003063 SpvId value = this->writeExpression(*s.value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003064 std::vector<SpvId> labels;
3065 SpvId end = this->nextId();
3066 SpvId defaultLabel = end;
3067 fBreakTarget.push(end);
3068 int size = 3;
John Stiles2d4f9592020-10-30 10:29:12 -04003069 auto& cases = s.cases();
3070 for (const std::unique_ptr<SwitchCase>& c : cases) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003071 SpvId label = this->nextId();
3072 labels.push_back(label);
John Stiles2d4f9592020-10-30 10:29:12 -04003073 if (c->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003074 size += 2;
3075 } else {
3076 defaultLabel = label;
3077 }
3078 }
3079 labels.push_back(end);
3080 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3081 this->writeOpCode(SpvOpSwitch, size, out);
3082 this->writeWord(value, out);
3083 this->writeWord(defaultLabel, out);
John Stiles2d4f9592020-10-30 10:29:12 -04003084 for (size_t i = 0; i < cases.size(); ++i) {
3085 if (!cases[i]->value()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003086 continue;
3087 }
John Stiles2d4f9592020-10-30 10:29:12 -04003088 this->writeWord(cases[i]->value()->as<IntLiteral>().value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003089 this->writeWord(labels[i], out);
3090 }
John Stiles2d4f9592020-10-30 10:29:12 -04003091 for (size_t i = 0; i < cases.size(); ++i) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003092 this->writeLabel(labels[i], out);
John Stiles2d4f9592020-10-30 10:29:12 -04003093 for (const auto& stmt : cases[i]->statements()) {
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003094 this->writeStatement(*stmt, out);
3095 }
3096 if (fCurrentBlock) {
3097 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3098 }
3099 }
3100 this->writeLabel(end, out);
3101 fBreakTarget.pop();
3102}
3103
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003104void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003105 if (r.expression()) {
3106 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.expression(), out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003107 out);
3108 } else {
3109 this->writeInstruction(SpvOpReturn, out);
3110 }
3111}
3112
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003113void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003114 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003115 int invocations = 1;
Brian Osman133724c2020-10-28 14:14:39 -04003116 for (const ProgramElement* e : fProgram.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003117 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04003118 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003119 if (m.fFlags & Modifiers::kIn_Flag) {
3120 if (m.fLayout.fInvocations != -1) {
3121 invocations = m.fLayout.fInvocations;
3122 }
3123 SpvId input;
3124 switch (m.fLayout.fPrimitive) {
3125 case Layout::kPoints_Primitive:
3126 input = SpvExecutionModeInputPoints;
3127 break;
3128 case Layout::kLines_Primitive:
3129 input = SpvExecutionModeInputLines;
3130 break;
3131 case Layout::kLinesAdjacency_Primitive:
3132 input = SpvExecutionModeInputLinesAdjacency;
3133 break;
3134 case Layout::kTriangles_Primitive:
3135 input = SpvExecutionModeTriangles;
3136 break;
3137 case Layout::kTrianglesAdjacency_Primitive:
3138 input = SpvExecutionModeInputTrianglesAdjacency;
3139 break;
3140 default:
3141 input = 0;
3142 break;
3143 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003144 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003145 if (input) {
3146 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3147 }
3148 } else if (m.fFlags & Modifiers::kOut_Flag) {
3149 SpvId output;
3150 switch (m.fLayout.fPrimitive) {
3151 case Layout::kPoints_Primitive:
3152 output = SpvExecutionModeOutputPoints;
3153 break;
3154 case Layout::kLineStrip_Primitive:
3155 output = SpvExecutionModeOutputLineStrip;
3156 break;
3157 case Layout::kTriangleStrip_Primitive:
3158 output = SpvExecutionModeOutputTriangleStrip;
3159 break;
3160 default:
3161 output = 0;
3162 break;
3163 }
3164 if (output) {
3165 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3166 }
3167 if (m.fLayout.fMaxVertices != -1) {
3168 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3169 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3170 out);
3171 }
3172 }
3173 }
3174 }
3175 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3176 invocations, out);
3177}
3178
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003179void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003180 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003181 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003182 std::set<SpvId> interfaceVars;
Brian Osman1f8f5752020-10-28 14:46:21 -04003183 // assign IDs to functions
Brian Osman133724c2020-10-28 14:14:39 -04003184 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003185 switch (e->kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04003186 case ProgramElement::Kind::kFunction: {
Brian Osman1179fcf2020-10-08 16:04:40 -04003187 const FunctionDefinition& f = e->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04003188 fFunctionMap[&f.declaration()] = this->nextId();
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003189 break;
3190 }
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003191 default:
3192 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003193 }
3194 }
Brian Osman133724c2020-10-28 14:14:39 -04003195 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003196 if (e->is<InterfaceBlock>()) {
Brian Osman1f8f5752020-10-28 14:46:21 -04003197 const InterfaceBlock& intf = e->as<InterfaceBlock>();
ethannicholasb3058bd2016-07-01 08:22:01 -07003198 SpvId id = this->writeInterfaceBlock(intf);
Brian Osman1f8f5752020-10-28 14:46:21 -04003199
3200 const Modifiers& modifiers = intf.variable().modifiers();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003201 if (((modifiers.fFlags & Modifiers::kIn_Flag) ||
3202 (modifiers.fFlags & Modifiers::kOut_Flag)) &&
3203 modifiers.fLayout.fBuiltin == -1 &&
Brian Osman010ce6a2020-10-19 16:34:10 -04003204 !is_dead(intf.variable(), fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003205 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003206 }
3207 }
3208 }
Brian Osman133724c2020-10-28 14:14:39 -04003209 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003210 if (e->is<GlobalVarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04003211 this->writeGlobalVar(program.fKind,
3212 e->as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>(),
3213 body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003214 }
3215 }
Brian Osman133724c2020-10-28 14:14:39 -04003216 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003217 if (e->is<FunctionDefinition>()) {
3218 this->writeFunction(e->as<FunctionDefinition>(), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003219 }
3220 }
ethannicholasd598f792016-07-25 10:08:54 -07003221 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003222 for (auto entry : fFunctionMap) {
Ethan Nicholase2c49992020-10-05 11:49:11 -04003223 if (entry.first->name() == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003224 main = entry.first;
3225 }
3226 }
Ethan Nicholas1a668d22019-04-18 10:37:40 -04003227 if (!main) {
3228 fErrors.error(0, "program does not contain a main() function");
3229 return;
3230 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003231 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003232 const Variable* var = entry.first;
Ethan Nicholas453f67f2020-10-09 10:43:45 -04003233 if (var->storage() == Variable::Storage::kGlobal &&
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003234 ((var->modifiers().fFlags & Modifiers::kIn_Flag) ||
Brian Osman010ce6a2020-10-19 16:34:10 -04003235 (var->modifiers().fFlags & Modifiers::kOut_Flag)) &&
3236 !is_dead(*var, fProgram.fUsage.get())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003237 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003238 }
3239 }
3240 this->writeCapabilities(out);
3241 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3242 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003243 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->name().fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003244 (int32_t) interfaceVars.size(), out);
3245 switch (program.fKind) {
3246 case Program::kVertex_Kind:
3247 this->writeWord(SpvExecutionModelVertex, out);
3248 break;
3249 case Program::kFragment_Kind:
3250 this->writeWord(SpvExecutionModelFragment, out);
3251 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003252 case Program::kGeometry_Kind:
3253 this->writeWord(SpvExecutionModelGeometry, out);
3254 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003255 default:
3256 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003257 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003258 SpvId entryPoint = fFunctionMap[main];
3259 this->writeWord(entryPoint, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003260 this->writeString(main->name().fChars, main->name().fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003261 for (int var : interfaceVars) {
3262 this->writeWord(var, out);
3263 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003264 if (program.fKind == Program::kGeometry_Kind) {
3265 this->writeGeometryShaderExecutionMode(entryPoint, out);
3266 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003267 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003268 this->writeInstruction(SpvOpExecutionMode,
3269 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003270 SpvExecutionModeOriginUpperLeft,
3271 out);
3272 }
Brian Osman133724c2020-10-28 14:14:39 -04003273 for (const ProgramElement* e : program.elements()) {
Brian Osman1179fcf2020-10-08 16:04:40 -04003274 if (e->is<Extension>()) {
3275 this->writeInstruction(SpvOpSourceExtension, e->as<Extension>().name().c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003276 }
3277 }
Greg Daniel64773e62016-11-22 09:44:03 -05003278
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003279 write_stringstream(fExtraGlobalsBuffer, out);
3280 write_stringstream(fNameBuffer, out);
3281 write_stringstream(fDecorationBuffer, out);
3282 write_stringstream(fConstantBuffer, out);
3283 write_stringstream(fExternalFunctionsBuffer, out);
3284 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003285}
3286
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003287bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003288 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003289 this->writeWord(SpvMagicNumber, *fOut);
3290 this->writeWord(SpvVersion, *fOut);
3291 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003292 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003293 this->writeInstructions(fProgram, buffer);
3294 this->writeWord(fIdCount, *fOut);
3295 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003296 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003297 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003298}
3299
John Stilesa6841be2020-08-06 14:11:56 -04003300} // namespace SkSL