blob: ac70d8f3a0b5dcfbaa0ea0b6a407d68ea361d649 [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);
Ethan Nicholas0df1b042017-03-31 13:56:23 -040080 fIntrinsicMap[String("step")] = ALL_GLSL(Step);
81 fIntrinsicMap[String("smoothstep")] = ALL_GLSL(SmoothStep);
82 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];
399 size_t size = memoryLayout.size(*field.fType);
400 size_t alignment = memoryLayout.alignment(*field.fType);
401 const Layout& fieldLayout = field.fModifiers.fLayout;
Ethan Nicholas19671772016-11-28 16:30:17 -0500402 if (fieldLayout.fOffset >= 0) {
Greg Danieldbd44c72017-01-24 15:12:12 -0500403 if (fieldLayout.fOffset < (int) offset) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700404 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400405 "offset of field '" + field.fName + "' must be at "
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500406 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -0500407 }
408 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700409 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400410 "offset of field '" + field.fName + "' must be a multiple"
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500411 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -0500412 }
413 offset = fieldLayout.fOffset;
414 } else {
415 size_t mod = offset % alignment;
416 if (mod) {
417 offset += alignment - mod;
418 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700419 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400420 this->writeInstruction(SpvOpMemberName, resultId, i, field.fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500421 this->writeLayout(fieldLayout, resultId, i);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400422 if (field.fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -0500423 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700424 (SpvId) offset, fDecorationBuffer);
425 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400426 if (field.fType->typeKind() == Type::TypeKind::kMatrix) {
Greg Daniel64773e62016-11-22 09:44:03 -0500427 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -0700428 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500429 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400430 (SpvId) memoryLayout.stride(*field.fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800431 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700432 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400433 if (!field.fType->highPrecision()) {
434 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i,
435 SpvDecorationRelaxedPrecision, fDecorationBuffer);
436 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700437 offset += size;
Ethan Nicholase6592142020-09-08 10:22:09 -0400438 Type::TypeKind kind = field.fType->typeKind();
439 if ((kind == Type::TypeKind::kArray || kind == Type::TypeKind::kStruct) &&
440 offset % alignment != 0) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700441 offset += alignment - offset % alignment;
442 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700443 }
444}
445
Ethan Nicholase2c49992020-10-05 11:49:11 -0400446const Type& SPIRVCodeGenerator::getActualType(const Type& type) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500447 if (type.isFloat()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400448 return *fContext.fFloat_Type;
449 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500450 if (type.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400451 return *fContext.fInt_Type;
452 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500453 if (type.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400454 return *fContext.fUInt_Type;
455 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400456 if (type.typeKind() == Type::TypeKind::kMatrix || type.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400457 if (type.componentType() == *fContext.fHalf_Type) {
458 return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
459 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400460 if (type.componentType() == *fContext.fShort_Type ||
461 type.componentType() == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400462 return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
463 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400464 if (type.componentType() == *fContext.fUShort_Type ||
465 type.componentType() == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400466 return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
467 }
468 }
469 return type;
470}
471
ethannicholasb3058bd2016-07-01 08:22:01 -0700472SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800473 return this->getType(type, fDefaultLayout);
474}
475
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400476SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400477 const Type& type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400478 String key = type.name() + to_string((int) layout.fStd);
ethannicholas8ac838d2016-11-22 08:39:36 -0800479 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700480 if (entry == fTypeMap.end()) {
481 SpvId result = this->nextId();
Ethan Nicholase6592142020-09-08 10:22:09 -0400482 switch (type.typeKind()) {
483 case Type::TypeKind::kScalar:
ethannicholasd598f792016-07-25 10:08:54 -0700484 if (type == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700485 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500486 } else if (type == *fContext.fInt_Type || type == *fContext.fShort_Type ||
487 type == *fContext.fIntLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700488 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500489 } else if (type == *fContext.fUInt_Type || type == *fContext.fUShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700490 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500491 } else if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type ||
492 type == *fContext.fFloatLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700493 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700494 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400495 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700496 }
497 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400498 case Type::TypeKind::kVector:
Greg Daniel64773e62016-11-22 09:44:03 -0500499 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800500 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700501 type.columns(), fConstantBuffer);
502 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400503 case Type::TypeKind::kMatrix:
Greg Daniel64773e62016-11-22 09:44:03 -0500504 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800505 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700506 type.columns(), fConstantBuffer);
507 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400508 case Type::TypeKind::kStruct:
ethannicholas8ac838d2016-11-22 08:39:36 -0800509 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700510 break;
Ethan Nicholase6592142020-09-08 10:22:09 -0400511 case Type::TypeKind::kArray: {
ethannicholasb3058bd2016-07-01 08:22:01 -0700512 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700513 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500514 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800515 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700516 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500517 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400518 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800519 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700520 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400521 SkASSERT(false); // we shouldn't have any runtime-sized arrays right now
Greg Daniel64773e62016-11-22 09:44:03 -0500522 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800523 this->getType(type.componentType(), layout),
524 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400525 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
526 (int32_t) layout.stride(type),
527 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700528 }
529 break;
530 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400531 case Type::TypeKind::kSampler: {
Greg Daniel64773e62016-11-22 09:44:03 -0500532 SpvId image = result;
533 if (SpvDimSubpassData != type.dimensions()) {
Stephen White792e2302019-08-09 13:33:51 -0400534 image = this->getType(type.textureType(), layout);
Greg Daniel64773e62016-11-22 09:44:03 -0500535 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400536 if (SpvDimBuffer == type.dimensions()) {
537 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
538 }
Greg Daniel64773e62016-11-22 09:44:03 -0500539 if (SpvDimSubpassData != type.dimensions()) {
540 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
541 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700542 break;
543 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400544 case Type::TypeKind::kSeparateSampler: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400545 this->writeInstruction(SpvOpTypeSampler, result, fConstantBuffer);
546 break;
547 }
Ethan Nicholase6592142020-09-08 10:22:09 -0400548 case Type::TypeKind::kTexture: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400549 this->writeInstruction(SpvOpTypeImage, result,
550 this->getType(*fContext.fFloat_Type, layout),
Stephen White792e2302019-08-09 13:33:51 -0400551 type.dimensions(), type.isDepth(), type.isArrayed(),
552 type.isMultisampled(), type.isSampled() ? 1 : 2,
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400553 SpvImageFormatUnknown, fConstantBuffer);
554 fImageTypeMap[key] = result;
555 break;
556 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700557 default:
ethannicholasd598f792016-07-25 10:08:54 -0700558 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700559 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
560 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500561#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700562 ABORT("invalid type: %s", type.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500563#endif
ethannicholasb3058bd2016-07-01 08:22:01 -0700564 }
565 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800566 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700567 return result;
568 }
569 return entry->second;
570}
571
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400572SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400573 SkASSERT(type.typeKind() == Type::TypeKind::kSampler);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400574 this->getType(type);
575 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400576 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400577 return fImageTypeMap[key];
578}
579
ethannicholasd598f792016-07-25 10:08:54 -0700580SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400581 String key = to_string(this->getType(function.returnType())) + "(";
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400582 String separator;
Brian Osman5bf3e202020-10-13 10:34:18 -0400583 const std::vector<const Variable*>& parameters = function.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -0400584 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700585 key += separator;
586 separator = ", ";
Ethan Nicholased84b732020-10-08 11:45:44 -0400587 key += to_string(this->getType(parameters[i]->type()));
ethannicholasb3058bd2016-07-01 08:22:01 -0700588 }
589 key += ")";
590 auto entry = fTypeMap.find(key);
591 if (entry == fTypeMap.end()) {
592 SpvId result = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -0400593 int32_t length = 3 + (int32_t) parameters.size();
594 SpvId returnType = this->getType(function.returnType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700595 std::vector<SpvId> parameterTypes;
Ethan Nicholased84b732020-10-08 11:45:44 -0400596 for (size_t i = 0; i < parameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -0500597 // glslang seems to treat all function arguments as pointers whether they need to be or
598 // not. I was initially puzzled by this until I ran bizarre failures with certain
599 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -0700600 // failure case:
601 //
602 // void sphere(float x) {
603 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500604 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700605 // void map() {
606 // sphere(1.0);
607 // }
Greg Daniel64773e62016-11-22 09:44:03 -0500608 //
ethannicholasb3058bd2016-07-01 08:22:01 -0700609 // void main() {
610 // for (int i = 0; i < 1; i++) {
611 // map();
612 // }
613 // }
614 //
Greg Daniel64773e62016-11-22 09:44:03 -0500615 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
616 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -0700617 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
618 // the spec makes this make sense.
619// if (is_out(function->fParameters[i])) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400620 parameterTypes.push_back(this->getPointerType(parameters[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -0700621 SpvStorageClassFunction));
622// } else {
ethannicholasd598f792016-07-25 10:08:54 -0700623// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700624// }
625 }
626 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
627 this->writeWord(result, fConstantBuffer);
628 this->writeWord(returnType, fConstantBuffer);
629 for (SpvId id : parameterTypes) {
630 this->writeWord(id, fConstantBuffer);
631 }
632 fTypeMap[key] = result;
633 return result;
634 }
635 return entry->second;
636}
637
ethannicholas8ac838d2016-11-22 08:39:36 -0800638SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
639 return this->getPointerType(type, fDefaultLayout, storageClass);
640}
641
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400642SpvId SPIRVCodeGenerator::getPointerType(const Type& rawType, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -0700643 SpvStorageClass_ storageClass) {
Ethan Nicholase2c49992020-10-05 11:49:11 -0400644 const Type& type = this->getActualType(rawType);
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500645 String key = type.displayName() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -0700646 auto entry = fTypeMap.find(key);
647 if (entry == fTypeMap.end()) {
648 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -0500649 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -0700650 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700651 fTypeMap[key] = result;
652 return result;
653 }
654 return entry->second;
655}
656
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400657SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -0400658 switch (expr.kind()) {
659 case Expression::Kind::kBinary:
John Stiles81365af2020-08-18 09:24:00 -0400660 return this->writeBinaryExpression(expr.as<BinaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400661 case Expression::Kind::kBoolLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400662 return this->writeBoolLiteral(expr.as<BoolLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400663 case Expression::Kind::kConstructor:
John Stiles81365af2020-08-18 09:24:00 -0400664 return this->writeConstructor(expr.as<Constructor>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400665 case Expression::Kind::kIntLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400666 return this->writeIntLiteral(expr.as<IntLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400667 case Expression::Kind::kFieldAccess:
John Stiles81365af2020-08-18 09:24:00 -0400668 return this->writeFieldAccess(expr.as<FieldAccess>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400669 case Expression::Kind::kFloatLiteral:
John Stiles81365af2020-08-18 09:24:00 -0400670 return this->writeFloatLiteral(expr.as<FloatLiteral>());
Ethan Nicholase6592142020-09-08 10:22:09 -0400671 case Expression::Kind::kFunctionCall:
John Stiles81365af2020-08-18 09:24:00 -0400672 return this->writeFunctionCall(expr.as<FunctionCall>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400673 case Expression::Kind::kPrefix:
John Stiles81365af2020-08-18 09:24:00 -0400674 return this->writePrefixExpression(expr.as<PrefixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400675 case Expression::Kind::kPostfix:
John Stiles81365af2020-08-18 09:24:00 -0400676 return this->writePostfixExpression(expr.as<PostfixExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400677 case Expression::Kind::kSwizzle:
John Stiles81365af2020-08-18 09:24:00 -0400678 return this->writeSwizzle(expr.as<Swizzle>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400679 case Expression::Kind::kVariableReference:
John Stiles81365af2020-08-18 09:24:00 -0400680 return this->writeVariableReference(expr.as<VariableReference>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400681 case Expression::Kind::kTernary:
John Stiles81365af2020-08-18 09:24:00 -0400682 return this->writeTernaryExpression(expr.as<TernaryExpression>(), out);
Ethan Nicholase6592142020-09-08 10:22:09 -0400683 case Expression::Kind::kIndex:
John Stiles81365af2020-08-18 09:24:00 -0400684 return this->writeIndexExpression(expr.as<IndexExpression>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700685 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500686#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -0700687 ABORT("unsupported expression: %s", expr.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -0500688#endif
689 break;
ethannicholasb3058bd2016-07-01 08:22:01 -0700690 }
691 return -1;
692}
693
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400694SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400695 const FunctionDeclaration& function = c.function();
John Stiles8e3b6be2020-10-13 11:14:08 -0400696 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400697 auto intrinsic = fIntrinsicMap.find(function.name());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400698 SkASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -0700699 int32_t intrinsicId;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400700 if (arguments.size() > 0) {
701 const Type& type = arguments[0]->type();
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400702 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
703 intrinsicId = std::get<1>(intrinsic->second);
704 } else if (is_signed(fContext, type)) {
705 intrinsicId = std::get<2>(intrinsic->second);
706 } else if (is_unsigned(fContext, type)) {
707 intrinsicId = std::get<3>(intrinsic->second);
708 } else if (is_bool(fContext, type)) {
709 intrinsicId = std::get<4>(intrinsic->second);
710 } else {
711 intrinsicId = std::get<1>(intrinsic->second);
712 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700713 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400714 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700715 }
716 switch (std::get<0>(intrinsic->second)) {
717 case kGLSL_STD_450_IntrinsicKind: {
718 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400719 std::vector<SpvId> argumentIds;
720 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400721 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400722 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400723 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400724 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400725 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700726 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400727 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400728 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700729 this->writeWord(result, out);
730 this->writeWord(fGLSLExtendedInstructions, out);
731 this->writeWord(intrinsicId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400732 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700733 this->writeWord(id, out);
734 }
735 return result;
736 }
737 case kSPIRV_IntrinsicKind: {
738 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400739 std::vector<SpvId> argumentIds;
740 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholased84b732020-10-08 11:45:44 -0400741 if (function.parameters()[i]->modifiers().fFlags & Modifiers::kOut_Flag) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400742 argumentIds.push_back(this->getLValue(*arguments[i], out)->getPointer());
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400743 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400744 argumentIds.push_back(this->writeExpression(*arguments[i], out));
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400745 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700746 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400747 if (c.type() != *fContext.fVoid_Type) {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400748 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400749 this->writeWord(this->getType(c.type()), out);
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400750 this->writeWord(result, out);
751 } else {
752 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
753 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400754 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700755 this->writeWord(id, out);
756 }
757 return result;
758 }
759 case kSpecial_IntrinsicKind:
760 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
761 default:
762 ABORT("unsupported intrinsic kind");
763 }
764}
765
John Stiles8e3b6be2020-10-13 11:14:08 -0400766std::vector<SpvId> SPIRVCodeGenerator::vectorize(const ExpressionArray& args, OutputStream& out) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500767 int vectorSize = 0;
768 for (const auto& a : args) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400769 if (a->type().typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500770 if (vectorSize) {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400771 SkASSERT(a->type().columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500772 }
773 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400774 vectorSize = a->type().columns();
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500775 }
776 }
777 }
778 std::vector<SpvId> result;
John Stiles8e3b6be2020-10-13 11:14:08 -0400779 result.reserve(args.size());
Ethan Nicholas30d30222020-09-11 12:27:26 -0400780 for (const auto& arg : args) {
781 const Type& argType = arg->type();
782 SpvId raw = this->writeExpression(*arg, out);
783 if (vectorSize && argType.typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500784 SpvId vector = this->nextId();
785 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400786 this->writeWord(this->getType(argType.toCompound(fContext, vectorSize, 1)), out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500787 this->writeWord(vector, out);
788 for (int i = 0; i < vectorSize; i++) {
789 this->writeWord(raw, out);
790 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400791 this->writePrecisionModifier(argType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500792 result.push_back(vector);
793 } else {
794 result.push_back(raw);
795 }
796 }
797 return result;
798}
799
800void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
801 SpvId signedInst, SpvId unsignedInst,
802 const std::vector<SpvId>& args,
803 OutputStream& out) {
804 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
805 this->writeWord(this->getType(type), out);
806 this->writeWord(id, out);
807 this->writeWord(fGLSLExtendedInstructions, out);
808
809 if (is_float(fContext, type)) {
810 this->writeWord(floatInst, out);
811 } else if (is_signed(fContext, type)) {
812 this->writeWord(signedInst, out);
813 } else if (is_unsigned(fContext, type)) {
814 this->writeWord(unsignedInst, out);
815 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400816 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500817 }
818 for (SpvId a : args) {
819 this->writeWord(a, out);
820 }
821}
822
Greg Daniel64773e62016-11-22 09:44:03 -0500823SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400824 OutputStream& out) {
John Stiles8e3b6be2020-10-13 11:14:08 -0400825 const ExpressionArray& arguments = c.arguments();
ethannicholasb3058bd2016-07-01 08:22:01 -0700826 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400827 const Type& callType = c.type();
ethannicholasb3058bd2016-07-01 08:22:01 -0700828 switch (kind) {
829 case kAtan_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400830 std::vector<SpvId> argumentIds;
831 for (const std::unique_ptr<Expression>& arg : arguments) {
832 argumentIds.push_back(this->writeExpression(*arg, out));
ethannicholasb3058bd2016-07-01 08:22:01 -0700833 }
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400834 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) argumentIds.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400835 this->writeWord(this->getType(callType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700836 this->writeWord(result, out);
837 this->writeWord(fGLSLExtendedInstructions, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400838 this->writeWord(argumentIds.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
839 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700840 this->writeWord(id, out);
841 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400842 break;
843 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400844 case kSampledImage_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400845 SkASSERT(arguments.size() == 2);
846 SpvId img = this->writeExpression(*arguments[0], out);
847 SpvId sampler = this->writeExpression(*arguments[1], out);
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400848 this->writeInstruction(SpvOpSampledImage,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400849 this->getType(callType),
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400850 result,
851 img,
852 sampler,
853 out);
854 break;
855 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400856 case kSubpassLoad_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400857 SpvId img = this->writeExpression(*arguments[0], out);
John Stiles8e3b6be2020-10-13 11:14:08 -0400858 ExpressionArray args;
John Stilesf4bda742020-10-14 16:57:41 -0400859 args.reserve_back(2);
John Stiles8e3b6be2020-10-13 11:14:08 -0400860 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
861 args.push_back(std::make_unique<IntLiteral>(fContext, /*offset=*/-1, /*value=*/0));
Ethan Nicholas30d30222020-09-11 12:27:26 -0400862 Constructor ctor(-1, fContext.fInt2_Type.get(), std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400863 SpvId coords = this->writeConstantVector(ctor);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400864 if (arguments.size() == 1) {
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400865 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400866 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400867 result,
868 img,
869 coords,
870 out);
871 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400872 SkASSERT(arguments.size() == 2);
873 SpvId sample = this->writeExpression(*arguments[1], out);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400874 this->writeInstruction(SpvOpImageRead,
Ethan Nicholas30d30222020-09-11 12:27:26 -0400875 this->getType(callType),
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400876 result,
877 img,
878 coords,
879 SpvImageOperandsSampleMask,
880 sample,
881 out);
882 }
883 break;
884 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700885 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500886 SpvOp_ op = SpvOpImageSampleImplicitLod;
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400887 const Type& arg1Type = arguments[1]->type();
888 switch (arguments[0]->type().dimensions()) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500889 case SpvDim1D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400890 if (arg1Type == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500891 op = SpvOpImageSampleProjImplicitLod;
892 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400893 SkASSERT(arg1Type == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500894 }
895 break;
896 case SpvDim2D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400897 if (arg1Type == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500898 op = SpvOpImageSampleProjImplicitLod;
899 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400900 SkASSERT(arg1Type == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500901 }
902 break;
903 case SpvDim3D:
Ethan Nicholas30d30222020-09-11 12:27:26 -0400904 if (arg1Type == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500905 op = SpvOpImageSampleProjImplicitLod;
906 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -0400907 SkASSERT(arg1Type == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500908 }
909 break;
910 case SpvDimCube: // fall through
911 case SpvDimRect: // fall through
912 case SpvDimBuffer: // fall through
913 case SpvDimSubpassData:
914 break;
915 }
Ethan Nicholas30d30222020-09-11 12:27:26 -0400916 SpvId type = this->getType(callType);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400917 SpvId sampler = this->writeExpression(*arguments[0], out);
918 SpvId uv = this->writeExpression(*arguments[1], out);
919 if (arguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500920 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700921 SpvImageOperandsBiasMask,
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400922 this->writeExpression(*arguments[2], out),
ethannicholasb3058bd2016-07-01 08:22:01 -0700923 out);
924 } else {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400925 SkASSERT(arguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500926 if (fProgram.fSettings.fSharpenTextures) {
927 FloatLiteral lodBias(fContext, -1, -0.5);
928 this->writeInstruction(op, type, result, sampler, uv,
929 SpvImageOperandsBiasMask,
930 this->writeFloatLiteral(lodBias),
931 out);
932 } else {
933 this->writeInstruction(op, type, result, sampler, uv,
934 out);
935 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700936 }
937 break;
938 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500939 case kMod_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400940 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400941 SkASSERT(args.size() == 2);
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400942 const Type& operandType = arguments[0]->type();
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500943 SpvOp_ op;
944 if (is_float(fContext, operandType)) {
945 op = SpvOpFMod;
946 } else if (is_signed(fContext, operandType)) {
947 op = SpvOpSMod;
948 } else if (is_unsigned(fContext, operandType)) {
949 op = SpvOpUMod;
950 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400951 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500952 return 0;
953 }
954 this->writeOpCode(op, 5, out);
955 this->writeWord(this->getType(operandType), out);
956 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500957 this->writeWord(args[0], out);
958 this->writeWord(args[1], out);
959 break;
960 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700961 case kDFdy_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400962 SpvId fn = this->writeExpression(*arguments[0], out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700963 this->writeOpCode(SpvOpDPdy, 4, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400964 this->writeWord(this->getType(callType), out);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700965 this->writeWord(result, out);
966 this->writeWord(fn, out);
967 if (fProgram.fSettings.fFlipY) {
968 // Flipping Y also negates the Y derivatives.
969 SpvId flipped = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -0400970 this->writeInstruction(SpvOpFNegate, this->getType(callType), flipped, result,
971 out);
972 this->writePrecisionModifier(callType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700973 return flipped;
974 }
975 break;
976 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500977 case kClamp_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400978 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400979 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400980 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500981 GLSLstd450UClamp, args, out);
982 break;
983 }
984 case kMax_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400985 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400986 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400987 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMax, GLSLstd450SMax,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500988 GLSLstd450UMax, args, out);
989 break;
990 }
991 case kMin_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400992 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400993 SkASSERT(args.size() == 2);
Ethan Nicholas30d30222020-09-11 12:27:26 -0400994 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMin, GLSLstd450SMin,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500995 GLSLstd450UMin, args, out);
996 break;
997 }
998 case kMix_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -0400999 std::vector<SpvId> args = this->vectorize(arguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001000 SkASSERT(args.size() == 3);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001001 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FMix, SpvOpUndef,
Ethan Nicholas0fc07f92018-02-27 15:25:47 -05001002 SpvOpUndef, args, out);
1003 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -05001004 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001005 case kSaturate_SpecialIntrinsic: {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001006 SkASSERT(arguments.size() == 1);
John Stiles8e3b6be2020-10-13 11:14:08 -04001007 ExpressionArray finalArgs;
John Stilesf4bda742020-10-14 16:57:41 -04001008 finalArgs.reserve_back(3);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001009 finalArgs.push_back(arguments[0]->clone());
John Stiles8e3b6be2020-10-13 11:14:08 -04001010 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1011 /*value=*/0));
1012 finalArgs.push_back(std::make_unique<FloatLiteral>(fContext, /*offset=*/-1,
1013 /*value=*/1));
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001014 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001015 this->writeGLSLExtendedInstruction(callType, result, GLSLstd450FClamp, GLSLstd450SClamp,
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -04001016 GLSLstd450UClamp, spvArgs, out);
1017 break;
1018 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001019 }
1020 return result;
1021}
1022
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001023SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001024 const FunctionDeclaration& function = c.function();
John Stiles8e3b6be2020-10-13 11:14:08 -04001025 const ExpressionArray& arguments = c.arguments();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001026 const auto& entry = fFunctionMap.find(&function);
ethannicholasb3058bd2016-07-01 08:22:01 -07001027 if (entry == fFunctionMap.end()) {
1028 return this->writeIntrinsicCall(c, out);
1029 }
1030 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001031 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001032 std::vector<SpvId> argumentIds;
1033 for (size_t i = 0; i < arguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001034 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001035 // passed directly
1036 SpvId tmpVar;
1037 // if we need a temporary var to store this argument, this is the value to store in the var
1038 SpvId tmpValueId;
Ethan Nicholased84b732020-10-08 11:45:44 -04001039 if (is_out(*function.parameters()[i])) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001040 std::unique_ptr<LValue> lv = this->getLValue(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001041 SpvId ptr = lv->getPointer();
1042 if (ptr) {
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001043 argumentIds.push_back(ptr);
ethannicholasb3058bd2016-07-01 08:22:01 -07001044 continue;
1045 } else {
1046 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1047 // copy it into a temp, call the function, read the value out of the temp, and then
1048 // update the lvalue.
1049 tmpValueId = lv->load(out);
1050 tmpVar = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001051 lvalues.push_back(std::make_tuple(tmpVar, &arguments[i]->type(), std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001052 }
1053 } else {
1054 // see getFunctionType for an explanation of why we're always using pointer parameters
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001055 tmpValueId = this->writeExpression(*arguments[i], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001056 tmpVar = this->nextId();
1057 }
Greg Daniel64773e62016-11-22 09:44:03 -05001058 this->writeInstruction(SpvOpVariable,
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001059 this->getPointerType(arguments[i]->type(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001060 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001061 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001062 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001063 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001064 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001065 argumentIds.push_back(tmpVar);
ethannicholasb3058bd2016-07-01 08:22:01 -07001066 }
1067 SpvId result = this->nextId();
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001068 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001069 this->writeWord(this->getType(c.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001070 this->writeWord(result, out);
1071 this->writeWord(entry->second, out);
Ethan Nicholas0dec9922020-10-05 15:51:52 -04001072 for (SpvId id : argumentIds) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001073 this->writeWord(id, out);
1074 }
1075 // now that the call is complete, we may need to update some lvalues with the new values of out
1076 // arguments
1077 for (const auto& tuple : lvalues) {
1078 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001079 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1080 out);
1081 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001082 std::get<2>(tuple)->store(load, out);
1083 }
1084 return result;
1085}
1086
ethannicholasf789b382016-08-03 12:43:36 -07001087SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001088 const Type& type = c.type();
1089 SkASSERT(type.typeKind() == Type::TypeKind::kVector && c.isCompileTimeConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001090 SpvId result = this->nextId();
1091 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001092 for (const std::unique_ptr<Expression>& arg : c.arguments()) {
1093 arguments.push_back(this->writeExpression(*arg, fConstantBuffer));
ethannicholasb3058bd2016-07-01 08:22:01 -07001094 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001095 SpvId typeId = this->getType(type);
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001096 if (c.arguments().size() == 1) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001097 // with a single argument, a vector will have all of its entries equal to the argument
Ethan Nicholas30d30222020-09-11 12:27:26 -04001098 this->writeOpCode(SpvOpConstantComposite, 3 + type.columns(), fConstantBuffer);
1099 this->writeWord(typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001100 this->writeWord(result, fConstantBuffer);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001101 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001102 this->writeWord(arguments[0], fConstantBuffer);
1103 }
1104 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001105 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.arguments().size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001106 fConstantBuffer);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001107 this->writeWord(typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001108 this->writeWord(result, fConstantBuffer);
1109 for (SpvId id : arguments) {
1110 this->writeWord(id, fConstantBuffer);
1111 }
1112 }
1113 return result;
1114}
1115
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001116SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001117 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001118 SkASSERT(c.arguments().size() == 1);
1119 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001120 SkASSERT(constructorType.isFloat());
1121 SkASSERT(argType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001122 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001123 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001124 if (argType.isSigned()) {
1125 this->writeInstruction(SpvOpConvertSToF, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001126 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001127 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001128 SkASSERT(argType.isUnsigned());
1129 this->writeInstruction(SpvOpConvertUToF, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001130 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001131 }
1132 return result;
1133}
1134
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001135SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001136 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001137 SkASSERT(c.arguments().size() == 1);
1138 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001139 SkASSERT(constructorType.isSigned());
1140 SkASSERT(argType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001141 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001142 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001143 if (argType.isFloat()) {
1144 this->writeInstruction(SpvOpConvertFToS, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001145 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001146 }
1147 else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001148 SkASSERT(argType.isUnsigned());
1149 this->writeInstruction(SpvOpBitcast, this->getType(constructorType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001150 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001151 }
1152 return result;
1153}
1154
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001155SpvId SPIRVCodeGenerator::writeUIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001156 const Type& constructorType = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001157 SkASSERT(c.arguments().size() == 1);
1158 const Type& argType = c.arguments()[0]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001159 SkASSERT(constructorType.isUnsigned());
1160 SkASSERT(argType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001161 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001162 SpvId parameter = this->writeExpression(*c.arguments()[0], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001163 if (argType.isFloat()) {
1164 this->writeInstruction(SpvOpConvertFToU, this->getType(constructorType), result, parameter,
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001165 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001166 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001167 SkASSERT(argType.isSigned());
1168 this->writeInstruction(SpvOpBitcast, this->getType(constructorType), result, parameter,
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001169 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001170 }
1171 return result;
1172}
1173
Ethan Nicholas84645e32017-02-09 13:57:14 -05001174void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001175 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001176 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001177 SpvId zeroId = this->writeFloatLiteral(zero);
1178 std::vector<SpvId> columnIds;
1179 for (int column = 0; column < type.columns(); column++) {
1180 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1181 out);
1182 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1183 out);
1184 SpvId columnId = this->nextId();
1185 this->writeWord(columnId, out);
1186 columnIds.push_back(columnId);
1187 for (int row = 0; row < type.columns(); row++) {
1188 this->writeWord(row == column ? diagonal : zeroId, out);
1189 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001190 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001191 }
1192 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1193 out);
1194 this->writeWord(this->getType(type), out);
1195 this->writeWord(id, out);
John Stilesf621e232020-08-25 13:33:02 -04001196 for (SpvId columnId : columnIds) {
1197 this->writeWord(columnId, out);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001198 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001199 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001200}
1201
1202void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001203 const Type& dstType, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001204 SkASSERT(srcType.typeKind() == Type::TypeKind::kMatrix);
1205 SkASSERT(dstType.typeKind() == Type::TypeKind::kMatrix);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001206 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001207 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1208 srcType.rows(),
1209 1));
1210 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1211 dstType.rows(),
1212 1));
1213 SpvId zeroId;
1214 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001215 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001216 zeroId = this->writeFloatLiteral(zero);
1217 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001218 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001219 zeroId = this->writeIntLiteral(zero);
1220 } else {
1221 ABORT("unsupported matrix component type");
1222 }
1223 SpvId zeroColumn = 0;
1224 SpvId columns[4];
1225 for (int i = 0; i < dstType.columns(); i++) {
1226 if (i < srcType.columns()) {
1227 // we're still inside the src matrix, copy the column
1228 SpvId srcColumn = this->nextId();
1229 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001230 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001231 SpvId dstColumn;
1232 if (srcType.rows() == dstType.rows()) {
1233 // columns are equal size, don't need to do anything
1234 dstColumn = srcColumn;
1235 }
1236 else if (dstType.rows() > srcType.rows()) {
1237 // dst column is bigger, need to zero-pad it
1238 dstColumn = this->nextId();
1239 int delta = dstType.rows() - srcType.rows();
1240 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1241 this->writeWord(dstColumnType, out);
1242 this->writeWord(dstColumn, out);
1243 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001244 for (int j = 0; j < delta; ++j) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001245 this->writeWord(zeroId, out);
1246 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001247 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001248 }
1249 else {
1250 // dst column is smaller, need to swizzle the src column
1251 dstColumn = this->nextId();
1252 int count = dstType.rows();
1253 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1254 this->writeWord(dstColumnType, out);
1255 this->writeWord(dstColumn, out);
1256 this->writeWord(srcColumn, out);
1257 this->writeWord(srcColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001258 for (int j = 0; j < count; j++) {
1259 this->writeWord(j, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001260 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001261 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001262 }
1263 columns[i] = dstColumn;
1264 } else {
1265 // we're past the end of the src matrix, need a vector of zeroes
1266 if (!zeroColumn) {
1267 zeroColumn = this->nextId();
1268 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1269 this->writeWord(dstColumnType, out);
1270 this->writeWord(zeroColumn, out);
John Stilesf621e232020-08-25 13:33:02 -04001271 for (int j = 0; j < dstType.rows(); ++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, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001275 }
1276 columns[i] = zeroColumn;
1277 }
1278 }
1279 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1280 this->writeWord(this->getType(dstType), out);
1281 this->writeWord(id, out);
1282 for (int i = 0; i < dstType.columns(); i++) {
1283 this->writeWord(columns[i], out);
1284 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001285 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001286}
1287
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001288void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1289 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001290 std::vector<SpvId>* columnIds,
1291 int* currentCount, int rows, SpvId entry,
1292 OutputStream& out) {
1293 SkASSERT(*currentCount < rows);
1294 ++(*currentCount);
1295 currentColumn->push_back(entry);
1296 if (*currentCount == rows) {
1297 *currentCount = 0;
1298 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1299 this->writeWord(columnType, out);
1300 SpvId columnId = this->nextId();
1301 this->writeWord(columnId, out);
1302 columnIds->push_back(columnId);
1303 for (SpvId id : *currentColumn) {
1304 this->writeWord(id, out);
1305 }
1306 currentColumn->clear();
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001307 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001308 }
1309}
1310
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001311SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001312 const Type& type = c.type();
1313 SkASSERT(type.typeKind() == Type::TypeKind::kMatrix);
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001314 SkASSERT(c.arguments().size() > 0);
1315 const Type& arg0Type = c.arguments()[0]->type();
ethannicholasb3058bd2016-07-01 08:22:01 -07001316 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1317 // an instruction
1318 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001319 for (size_t i = 0; i < c.arguments().size(); i++) {
1320 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001321 }
1322 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001323 int rows = type.rows();
1324 int columns = type.columns();
1325 if (arguments.size() == 1 && arg0Type.typeKind() == Type::TypeKind::kScalar) {
1326 this->writeUniformScaleMatrix(result, arguments[0], type, out);
1327 } else if (arguments.size() == 1 && arg0Type.typeKind() == Type::TypeKind::kMatrix) {
1328 this->writeMatrixCopy(result, arguments[0], arg0Type, type, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001329 } else if (arguments.size() == 1 &&
Ethan Nicholas30d30222020-09-11 12:27:26 -04001330 arg0Type.typeKind() == Type::TypeKind::kVector) {
1331 SkASSERT(type.rows() == 2 && type.columns() == 2);
1332 SkASSERT(arg0Type.columns() == 4);
1333 SpvId componentType = this->getType(type.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001334 SpvId v[4];
1335 for (int i = 0; i < 4; ++i) {
1336 v[i] = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001337 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i,
1338 out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001339 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001340 SpvId columnType = this->getType(type.componentType().toCompound(fContext, 2, 1));
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001341 SpvId column1 = this->nextId();
1342 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1343 SpvId column2 = this->nextId();
1344 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001345 this->writeInstruction(SpvOpCompositeConstruct, this->getType(type), result, column1,
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001346 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001347 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001348 SpvId columnType = this->getType(type.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001349 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001350 // ids of vectors and scalars we have written to the current column so far
1351 std::vector<SpvId> currentColumn;
1352 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001353 int currentCount = 0;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001354 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001355 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001356 const Type& argType = c.arguments()[i]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001357 if (currentCount == 0 && argType.typeKind() == Type::TypeKind::kVector &&
1358 argType.columns() == type.rows()) {
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001359 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001360 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001361 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001362 if (argType.columns() == 1) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001363 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1364 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001365 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001366 SpvId componentType = this->getType(argType.componentType());
1367 for (int j = 0; j < argType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001368 SpvId swizzle = this->nextId();
1369 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1370 arguments[i], j, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001371 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1372 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001373 }
1374 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001375 }
1376 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001377 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001378 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001379 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001380 this->writeWord(result, out);
1381 for (SpvId id : columnIds) {
1382 this->writeWord(id, out);
1383 }
1384 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001385 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001386 return result;
1387}
1388
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001389SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001390 const Type& type = c.type();
1391 SkASSERT(type.typeKind() == Type::TypeKind::kVector);
Brian Osmanb6b95732020-06-30 11:44:27 -04001392 if (c.isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001393 return this->writeConstantVector(c);
1394 }
1395 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1396 // an instruction
1397 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001398 for (size_t i = 0; i < c.arguments().size(); i++) {
1399 const Type& argType = c.arguments()[i]->type();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001400 if (argType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001401 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1402 // extract the components and convert them in that case manually. On top of that,
1403 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1404 // doesn't handle vector arguments at all, so we always extract vector components and
1405 // pass them into OpCreateComposite individually.
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001406 SpvId vec = this->writeExpression(*c.arguments()[i], out);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001407 SpvOp_ op = SpvOpUndef;
Ethan Nicholas30d30222020-09-11 12:27:26 -04001408 const Type& src = argType.componentType();
1409 const Type& dst = type.componentType();
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001410 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1411 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001412 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001413 return vec;
1414 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001415 } else if (src == *fContext.fInt_Type ||
1416 src == *fContext.fShort_Type ||
1417 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001418 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001419 } else if (src == *fContext.fUInt_Type ||
1420 src == *fContext.fUShort_Type ||
1421 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001422 op = SpvOpConvertUToF;
1423 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001424 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001425 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001426 } else if (dst == *fContext.fInt_Type ||
1427 dst == *fContext.fShort_Type ||
1428 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001429 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1430 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001431 } else if (src == *fContext.fInt_Type ||
1432 src == *fContext.fShort_Type ||
1433 src == *fContext.fByte_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001434 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001435 return vec;
1436 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001437 } else if (src == *fContext.fUInt_Type ||
1438 src == *fContext.fUShort_Type ||
1439 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001440 op = SpvOpBitcast;
1441 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001442 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001443 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001444 } else if (dst == *fContext.fUInt_Type ||
1445 dst == *fContext.fUShort_Type ||
1446 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001447 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1448 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001449 } else if (src == *fContext.fInt_Type ||
1450 src == *fContext.fShort_Type ||
1451 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001452 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001453 } else if (src == *fContext.fUInt_Type ||
1454 src == *fContext.fUShort_Type ||
1455 src == *fContext.fUByte_Type) {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001456 if (c.arguments().size() == 1) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001457 return vec;
1458 }
1459 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001460 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001461 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001462 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001463 for (int j = 0; j < argType.columns(); j++) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001464 SpvId swizzle = this->nextId();
1465 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1466 out);
1467 if (op != SpvOpUndef) {
1468 SpvId cast = this->nextId();
1469 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1470 arguments.push_back(cast);
1471 } else {
1472 arguments.push_back(swizzle);
1473 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001474 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001475 } else {
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001476 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001477 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001478 }
1479 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001480 if (arguments.size() == 1 && c.arguments()[0]->type().typeKind() == Type::TypeKind::kScalar) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001481 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(), out);
1482 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001483 this->writeWord(result, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001484 for (int i = 0; i < type.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001485 this->writeWord(arguments[0], out);
1486 }
1487 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001488 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001489 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001490 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001491 this->writeWord(result, out);
1492 for (SpvId id : arguments) {
1493 this->writeWord(id, out);
1494 }
1495 }
1496 return result;
1497}
1498
Ethan Nicholasbd553222017-07-18 15:54:59 -04001499SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001500 const Type& type = c.type();
1501 SkASSERT(type.typeKind() == Type::TypeKind::kArray);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001502 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1503 // an instruction
1504 std::vector<SpvId> arguments;
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001505 for (size_t i = 0; i < c.arguments().size(); i++) {
1506 arguments.push_back(this->writeExpression(*c.arguments()[i], out));
Ethan Nicholasbd553222017-07-18 15:54:59 -04001507 }
1508 SpvId result = this->nextId();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001509 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.arguments().size(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001510 this->writeWord(this->getType(type), out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001511 this->writeWord(result, out);
1512 for (SpvId id : arguments) {
1513 this->writeWord(id, out);
1514 }
1515 return result;
1516}
1517
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001518SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001519 const Type& type = c.type();
Ethan Nicholasf70f0442020-09-29 12:41:35 -04001520 if (c.arguments().size() == 1 &&
1521 this->getActualType(type) == this->getActualType(c.arguments()[0]->type())) {
1522 return this->writeExpression(*c.arguments()[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001523 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001524 if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001525 return this->writeFloatConstructor(c, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001526 } else if (type == *fContext.fInt_Type ||
1527 type == *fContext.fShort_Type ||
1528 type == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001529 return this->writeIntConstructor(c, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001530 } else if (type == *fContext.fUInt_Type ||
1531 type == *fContext.fUShort_Type ||
1532 type == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001533 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001534 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001535 switch (type.typeKind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001536 case Type::TypeKind::kVector:
ethannicholasb3058bd2016-07-01 08:22:01 -07001537 return this->writeVectorConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001538 case Type::TypeKind::kMatrix:
ethannicholasb3058bd2016-07-01 08:22:01 -07001539 return this->writeMatrixConstructor(c, out);
Ethan Nicholase6592142020-09-08 10:22:09 -04001540 case Type::TypeKind::kArray:
Ethan Nicholasbd553222017-07-18 15:54:59 -04001541 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001542 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001543#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07001544 ABORT("unsupported constructor: %s", c.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05001545#endif
1546 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07001547 }
1548}
1549
1550SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1551 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001552 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001553 return SpvStorageClassInput;
1554 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001555 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001556 return SpvStorageClassOutput;
1557 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001558 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001559 return SpvStorageClassPushConstant;
1560 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001561 return SpvStorageClassUniform;
1562 } else {
1563 return SpvStorageClassFunction;
1564 }
1565}
1566
ethannicholasf789b382016-08-03 12:43:36 -07001567SpvStorageClass_ get_storage_class(const Expression& expr) {
Ethan Nicholase6592142020-09-08 10:22:09 -04001568 switch (expr.kind()) {
1569 case Expression::Kind::kVariableReference: {
Ethan Nicholas78686922020-10-08 06:46:27 -04001570 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001571 if (var.storage() != Variable::Storage::kGlobal) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001572 return SpvStorageClassFunction;
1573 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001574 SpvStorageClass_ result = get_storage_class(var.modifiers());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001575 if (result == SpvStorageClassFunction) {
1576 result = SpvStorageClassPrivate;
1577 }
1578 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001579 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001580 case Expression::Kind::kFieldAccess:
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001581 return get_storage_class(*expr.as<FieldAccess>().base());
Ethan Nicholase6592142020-09-08 10:22:09 -04001582 case Expression::Kind::kIndex:
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001583 return get_storage_class(*expr.as<IndexExpression>().base());
ethannicholasb3058bd2016-07-01 08:22:01 -07001584 default:
1585 return SpvStorageClassFunction;
1586 }
1587}
1588
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001589std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001590 std::vector<SpvId> chain;
Ethan Nicholase6592142020-09-08 10:22:09 -04001591 switch (expr.kind()) {
1592 case Expression::Kind::kIndex: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001593 IndexExpression& indexExpr = (IndexExpression&) expr;
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001594 chain = this->getAccessChain(*indexExpr.base(), out);
1595 chain.push_back(this->writeExpression(*indexExpr.index(), out));
ethannicholasb3058bd2016-07-01 08:22:01 -07001596 break;
1597 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001598 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001599 FieldAccess& fieldExpr = (FieldAccess&) expr;
Ethan Nicholas7a95b202020-10-09 11:55:40 -04001600 chain = this->getAccessChain(*fieldExpr.base(), out);
1601 IntLiteral index(fContext, -1, fieldExpr.fieldIndex());
ethannicholasb3058bd2016-07-01 08:22:01 -07001602 chain.push_back(this->writeIntLiteral(index));
1603 break;
1604 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001605 default: {
1606 SpvId id = this->getLValue(expr, out)->getPointer();
1607 SkASSERT(id != 0);
1608 chain.push_back(id);
1609 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001610 }
1611 return chain;
1612}
1613
1614class PointerLValue : public SPIRVCodeGenerator::LValue {
1615public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001616 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1617 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001618 : fGen(gen)
1619 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001620 , fType(type)
1621 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001622
John Stiles1cf2c8d2020-08-13 22:58:04 -04001623 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001624 return fPointer;
1625 }
1626
John Stiles1cf2c8d2020-08-13 22:58:04 -04001627 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001628 SpvId result = fGen.nextId();
1629 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001630 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001631 return result;
1632 }
1633
John Stiles1cf2c8d2020-08-13 22:58:04 -04001634 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001635 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1636 }
1637
1638private:
1639 SPIRVCodeGenerator& fGen;
1640 const SpvId fPointer;
1641 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001642 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001643};
1644
1645class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1646public:
Greg Daniel64773e62016-11-22 09:44:03 -05001647 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001648 const Type& baseType, const Type& swizzleType,
1649 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001650 : fGen(gen)
1651 , fVecPointer(vecPointer)
1652 , fComponents(components)
1653 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001654 , fSwizzleType(swizzleType)
1655 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001656
John Stiles1cf2c8d2020-08-13 22:58:04 -04001657 SpvId getPointer() override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001658 return 0;
1659 }
1660
John Stiles1cf2c8d2020-08-13 22:58:04 -04001661 SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001662 SpvId base = fGen.nextId();
1663 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001664 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001665 SpvId result = fGen.nextId();
1666 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1667 fGen.writeWord(fGen.getType(fSwizzleType), out);
1668 fGen.writeWord(result, out);
1669 fGen.writeWord(base, out);
1670 fGen.writeWord(base, out);
1671 for (int component : fComponents) {
1672 fGen.writeWord(component, out);
1673 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001674 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001675 return result;
1676 }
1677
John Stiles1cf2c8d2020-08-13 22:58:04 -04001678 void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001679 // use OpVectorShuffle to mix and match the vector components. We effectively create
1680 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001681 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001682 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001683 // float3L = ...;
1684 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001685 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001686 // 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 -07001687 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1688 // (3, 1, 4).
1689 SpvId base = fGen.nextId();
1690 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1691 SpvId shuffle = fGen.nextId();
1692 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1693 fGen.writeWord(fGen.getType(fBaseType), out);
1694 fGen.writeWord(shuffle, out);
1695 fGen.writeWord(base, out);
1696 fGen.writeWord(value, out);
1697 for (int i = 0; i < fBaseType.columns(); i++) {
1698 // current offset into the virtual vector, defaults to pulling the unmodified
1699 // value from the left side
1700 int offset = i;
1701 // check to see if we are writing this component
1702 for (size_t j = 0; j < fComponents.size(); j++) {
1703 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001704 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001705 // the correct component of the right side instead of preserving the
1706 // value from the left
1707 offset = (int) (j + fBaseType.columns());
1708 break;
1709 }
1710 }
1711 fGen.writeWord(offset, out);
1712 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001713 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001714 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1715 }
1716
1717private:
1718 SPIRVCodeGenerator& fGen;
1719 const SpvId fVecPointer;
1720 const std::vector<int>& fComponents;
1721 const Type& fBaseType;
1722 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001723 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001724};
1725
Greg Daniel64773e62016-11-22 09:44:03 -05001726std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001727 OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001728 const Type& type = expr.type();
1729 Precision precision = type.highPrecision() ? Precision::kHigh : Precision::kLow;
Ethan Nicholase6592142020-09-08 10:22:09 -04001730 switch (expr.kind()) {
1731 case Expression::Kind::kVariableReference: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001732 SpvId typeId;
Ethan Nicholas78686922020-10-08 06:46:27 -04001733 const Variable& var = *expr.as<VariableReference>().variable();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001734 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001735 typeId = this->getType(Type("sk_in", Type::TypeKind::kArray,
1736 var.type().componentType(), fSkInCount));
Ethan Nicholas5226b772018-05-03 16:20:41 -04001737 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001738 typeId = this->getType(type);
Ethan Nicholas5226b772018-05-03 16:20:41 -04001739 }
ethannicholasd598f792016-07-25 10:08:54 -07001740 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001741 SkASSERT(entry != fVariableMap.end());
Ethan Nicholas5226b772018-05-03 16:20:41 -04001742 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(*this,
1743 entry->second,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001744 typeId,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001745 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001746 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001747 case Expression::Kind::kIndex: // fall through
1748 case Expression::Kind::kFieldAccess: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001749 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1750 SpvId member = this->nextId();
1751 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001752 this->writeWord(this->getPointerType(type, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001753 this->writeWord(member, out);
1754 for (SpvId idx : chain) {
1755 this->writeWord(idx, out);
1756 }
1757 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas30d30222020-09-11 12:27:26 -04001758 *this,
1759 member,
1760 this->getType(type),
1761 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001762 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001763 case Expression::Kind::kSwizzle: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001764 Swizzle& swizzle = (Swizzle&) expr;
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001765 size_t count = swizzle.components().size();
1766 SpvId base = this->getLValue(*swizzle.base(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001767 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001768 if (count == 1) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001769 IntLiteral index(fContext, -1, swizzle.components()[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001770 SpvId member = this->nextId();
1771 this->writeInstruction(SpvOpAccessChain,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001772 this->getPointerType(type,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001773 get_storage_class(*swizzle.base())),
Greg Daniel64773e62016-11-22 09:44:03 -05001774 member,
1775 base,
1776 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001777 out);
1778 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas30d30222020-09-11 12:27:26 -04001779 *this,
1780 member,
1781 this->getType(type),
1782 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001783 } else {
1784 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
Ethan Nicholas30d30222020-09-11 12:27:26 -04001785 *this,
1786 base,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001787 swizzle.components(),
1788 swizzle.base()->type(),
Ethan Nicholas30d30222020-09-11 12:27:26 -04001789 type,
1790 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001791 }
1792 }
Ethan Nicholase6592142020-09-08 10:22:09 -04001793 case Expression::Kind::kTernary: {
Ethan Nicholasa583b812018-01-18 13:32:11 -05001794 TernaryExpression& t = (TernaryExpression&) expr;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001795 SpvId test = this->writeExpression(*t.test(), out);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001796 SpvId end = this->nextId();
1797 SpvId ifTrueLabel = this->nextId();
1798 SpvId ifFalseLabel = this->nextId();
1799 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1800 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1801 this->writeLabel(ifTrueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04001802 SpvId ifTrue = this->getLValue(*t.ifTrue(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001803 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001804 this->writeInstruction(SpvOpBranch, end, out);
1805 ifTrueLabel = fCurrentBlock;
Ethan Nicholasdd218162020-10-08 05:48:01 -04001806 SpvId ifFalse = this->getLValue(*t.ifFalse(), out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001807 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001808 ifFalseLabel = fCurrentBlock;
1809 this->writeInstruction(SpvOpBranch, end, out);
1810 SpvId result = this->nextId();
1811 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1812 ifTrueLabel, ifFalse, ifFalseLabel, out);
1813 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas30d30222020-09-11 12:27:26 -04001814 *this,
1815 result,
1816 this->getType(type),
1817 precision));
Ethan Nicholasa583b812018-01-18 13:32:11 -05001818 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04001819 default: {
ethannicholasb3058bd2016-07-01 08:22:01 -07001820 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001821 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001822 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1823 // caught by IRGenerator
1824 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001825 SpvId pointerType = this->getPointerType(type, SpvStorageClassFunction);
1826 this->writeInstruction(SpvOpVariable, pointerType, result, SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001827 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001828 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1829 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas30d30222020-09-11 12:27:26 -04001830 *this,
1831 result,
1832 this->getType(type),
1833 precision));
1834 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001835 }
1836}
1837
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001838SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001839 SpvId result = this->nextId();
Ethan Nicholas78686922020-10-08 06:46:27 -04001840 auto entry = fVariableMap.find(ref.variable());
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001841 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001842 SpvId var = entry->second;
Ethan Nicholas78686922020-10-08 06:46:27 -04001843 this->writeInstruction(SpvOpLoad, this->getType(ref.variable()->type()), result, var, out);
1844 this->writePrecisionModifier(ref.variable()->type(), result);
1845 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
Greg Daniela85e4bf2020-06-17 16:32:45 -04001846 (fProgram.fSettings.fFlipY || fProgram.fSettings.fInverseW)) {
1847 // The x component never changes, so just grab it
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001848 SpvId xId = this->nextId();
1849 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1850 result, 0, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001851
1852 // Calculate the y component which may need to be flipped
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001853 SpvId rawYId = this->nextId();
1854 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1855 result, 1, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001856 SpvId flippedYId = 0;
1857 if (fProgram.fSettings.fFlipY) {
1858 // need to remap to a top-left coordinate system
1859 if (fRTHeightStructId == (SpvId)-1) {
1860 // height variable hasn't been written yet
Greg Daniela85e4bf2020-06-17 16:32:45 -04001861 SkASSERT(fRTHeightFieldIndex == (SpvId)-1);
1862 std::vector<Type::Field> fields;
1863 SkASSERT(fProgram.fSettings.fRTHeightOffset >= 0);
1864 fields.emplace_back(
1865 Modifiers(Layout(0, -1, fProgram.fSettings.fRTHeightOffset, -1, -1, -1, -1,
1866 -1, Layout::Format::kUnspecified,
1867 Layout::kUnspecified_Primitive, 1, -1, "", "",
1868 Layout::kNo_Key, Layout::CType::kDefault),
1869 0),
1870 SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
1871 StringFragment name("sksl_synthetic_uniforms");
1872 Type intfStruct(-1, name, fields);
1873
1874 int binding = fProgram.fSettings.fRTHeightBinding;
1875 int set = fProgram.fSettings.fRTHeightSet;
1876 SkASSERT(binding != -1 && set != -1);
1877
1878 Layout layout(0, -1, -1, binding, -1, set, -1, -1, Layout::Format::kUnspecified,
1879 Layout::kUnspecified_Primitive, -1, -1, "", "", Layout::kNo_Key,
1880 Layout::CType::kDefault);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04001881 Modifiers modifiers(layout, Modifiers::kUniform_Flag);
John Stiles3ae071e2020-08-05 15:29:29 -04001882 const Variable* intfVar = fSynthetics.takeOwnershipOfSymbol(
1883 std::make_unique<Variable>(/*offset=*/-1,
Brian Osman8b43dad2020-10-09 13:31:42 -04001884 fProgram.fModifiers->handle(modifiers),
John Stiles3ae071e2020-08-05 15:29:29 -04001885 name,
Ethan Nicholas30d30222020-09-11 12:27:26 -04001886 &intfStruct,
Brian Osman3887a012020-09-30 13:22:27 -04001887 /*builtin=*/false,
Ethan Nicholas453f67f2020-10-09 10:43:45 -04001888 Variable::Storage::kGlobal));
John Stiles7c3515b2020-10-16 18:38:39 -04001889 InterfaceBlock intf(/*offset=*/-1, intfVar, name, /*instanceName=*/"",
1890 /*sizes=*/ExpressionArray(),
1891 std::make_shared<SymbolTable>(&fErrors, /*builtin=*/false));
Stephen White88574972020-06-23 19:09:29 -04001892
1893 fRTHeightStructId = this->writeInterfaceBlock(intf, false);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001894 fRTHeightFieldIndex = 0;
1895 }
1896 SkASSERT(fRTHeightFieldIndex != (SpvId)-1);
1897
1898 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1899 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1900 SpvId heightPtr = this->nextId();
1901 this->writeOpCode(SpvOpAccessChain, 5, out);
1902 this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform),
1903 out);
1904 this->writeWord(heightPtr, out);
1905 this->writeWord(fRTHeightStructId, out);
1906 this->writeWord(fieldIndexId, out);
1907 SpvId heightRead = this->nextId();
1908 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1909 heightPtr, out);
1910
1911 flippedYId = this->nextId();
1912 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
1913 heightRead, rawYId, out);
1914 }
1915
1916 // The z component will always be zero so we just get an id to the 0 literal
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001917 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001918 SpvId zeroId = writeFloatLiteral(zero);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001919
1920 // Calculate the w component which may need to be inverted
1921 SpvId rawWId = this->nextId();
1922 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawWId,
Ethan Nicholas20798e52018-12-04 12:30:50 -05001923 result, 3, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001924 SpvId invWId = 0;
1925 if (fProgram.fSettings.fInverseW) {
1926 // We need to invert w
1927 FloatLiteral one(fContext, -1, 1.0);
1928 SpvId oneId = writeFloatLiteral(one);
1929 invWId = this->nextId();
1930 this->writeInstruction(SpvOpFDiv, this->getType(*fContext.fFloat_Type), invWId, oneId,
1931 rawWId, out);
1932 }
1933
1934 // Fill in the new fragcoord with the components from above
1935 SpvId adjusted = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001936 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001937 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001938 this->writeWord(adjusted, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001939 this->writeWord(xId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001940 if (fProgram.fSettings.fFlipY) {
1941 this->writeWord(flippedYId, out);
1942 } else {
1943 this->writeWord(rawYId, out);
1944 }
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001945 this->writeWord(zeroId, out);
Greg Daniela85e4bf2020-06-17 16:32:45 -04001946 if (fProgram.fSettings.fInverseW) {
1947 this->writeWord(invWId, out);
1948 } else {
1949 this->writeWord(rawWId, out);
1950 }
1951
1952 return adjusted;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001953 }
Ethan Nicholas78686922020-10-08 06:46:27 -04001954 if (ref.variable()->modifiers().fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
Chris Daltonb91c4662018-08-01 10:46:22 -06001955 !fProgram.fSettings.fFlipY) {
1956 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1957 // the default convention of "counter-clockwise face is front".
1958 SpvId inverse = this->nextId();
1959 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1960 result, out);
1961 return inverse;
1962 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001963 return result;
1964}
1965
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001966SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04001967 if (expr.base()->type().typeKind() == Type::TypeKind::kVector) {
1968 SpvId base = this->writeExpression(*expr.base(), out);
1969 SpvId index = this->writeExpression(*expr.index(), out);
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001970 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04001971 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.type()), result, base,
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001972 index, out);
1973 return result;
1974 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001975 return getLValue(expr, out)->load(out);
1976}
1977
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001978SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001979 return getLValue(f, out)->load(out);
1980}
1981
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001982SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001983 SpvId base = this->writeExpression(*swizzle.base(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001984 SpvId result = this->nextId();
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001985 size_t count = swizzle.components().size();
ethannicholasb3058bd2016-07-01 08:22:01 -07001986 if (count == 1) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04001987 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.type()), result, base,
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001988 swizzle.components()[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001989 } else {
1990 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04001991 this->writeWord(this->getType(swizzle.type()), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001992 this->writeWord(result, out);
1993 this->writeWord(base, out);
Brian Osman25647672020-09-15 15:16:56 -04001994 this->writeWord(base, out);
Ethan Nicholas6b4d5812020-10-12 16:11:51 -04001995 for (int component : swizzle.components()) {
Brian Osman25647672020-09-15 15:16:56 -04001996 this->writeWord(component, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001997 }
1998 }
1999 return result;
2000}
2001
Greg Daniel64773e62016-11-22 09:44:03 -05002002SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
2003 const Type& operandType, SpvId lhs,
2004 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002005 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002006 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002007 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002008 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002009 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002010 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002011 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002012 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07002013 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002014 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002015 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07002016 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002017#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002018 ABORT("invalid operandType: %s", operandType.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002019#endif
ethannicholasb3058bd2016-07-01 08:22:01 -07002020 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04002021 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002022 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
2023 fDecorationBuffer);
2024 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002025 return result;
2026}
2027
Ethan Nicholas48e24052018-03-14 13:51:39 -04002028SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
2029 OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002030 if (operandType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002031 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04002032 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002033 return result;
2034 }
2035 return id;
2036}
2037
Ethan Nicholas68990be2017-07-13 09:36:52 -04002038SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
2039 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002040 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04002041 OutputStream& out) {
2042 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
Ethan Nicholase6592142020-09-08 10:22:09 -04002043 SkASSERT(operandType.typeKind() == Type::TypeKind::kMatrix);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002044 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2045 operandType.rows(),
2046 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04002047 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002048 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04002049 1));
2050 SpvId boolType = this->getType(*fContext.fBool_Type);
2051 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04002052 for (int i = 0; i < operandType.columns(); i++) {
2053 SpvId columnL = this->nextId();
2054 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2055 SpvId columnR = this->nextId();
2056 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002057 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002058 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
2059 SpvId merge = this->nextId();
2060 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002061 if (result != 0) {
2062 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002063 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002064 result = next;
2065 }
2066 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002067 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04002068 }
2069 }
2070 return result;
2071}
2072
Ethan Nicholas0df21132018-07-10 09:37:51 -04002073SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
2074 SpvId rhs, SpvOp_ floatOperator,
2075 SpvOp_ intOperator,
2076 OutputStream& out) {
2077 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
Ethan Nicholase6592142020-09-08 10:22:09 -04002078 SkASSERT(operandType.typeKind() == Type::TypeKind::kMatrix);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002079 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2080 operandType.rows(),
2081 1));
2082 SpvId columns[4];
2083 for (int i = 0; i < operandType.columns(); i++) {
2084 SpvId columnL = this->nextId();
2085 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2086 SpvId columnR = this->nextId();
2087 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2088 columns[i] = this->nextId();
2089 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2090 }
2091 SpvId result = this->nextId();
2092 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2093 this->writeWord(this->getType(operandType), out);
2094 this->writeWord(result, out);
2095 for (int i = 0; i < operandType.columns(); i++) {
2096 this->writeWord(columns[i], out);
2097 }
2098 return result;
2099}
2100
Ethan Nicholas49465b42019-04-17 12:22:21 -04002101std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2102 if (type.isInteger()) {
2103 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002104 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002105 else if (type.isFloat()) {
2106 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002107 } else {
Ethan Nicholase2c49992020-10-05 11:49:11 -04002108 ABORT("math is unsupported on type '%s'", String(type.name()).c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002109 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002110}
2111
2112SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Token::Kind op,
2113 const Type& rightType, SpvId rhs,
2114 const Type& resultType, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002115 Type tmp("<invalid>");
Ethan Nicholas48e24052018-03-14 13:51:39 -04002116 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002117 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002118 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2119 // handling in SPIR-V
Ethan Nicholas49465b42019-04-17 12:22:21 -04002120 if (this->getActualType(leftType) != this->getActualType(rightType)) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002121 if (leftType.typeKind() == Type::TypeKind::kVector && rightType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002122 if (op == Token::Kind::TK_SLASH) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002123 SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
2124 SpvId inverse = this->nextId();
2125 this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
2126 rhs = inverse;
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002127 op = Token::Kind::TK_STAR;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002128 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002129 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002130 SpvId result = this->nextId();
2131 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2132 result, lhs, rhs, out);
2133 return result;
2134 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002135 // promote number to vector
2136 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002137 const Type& vecType = leftType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002138 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2139 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002140 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002141 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002142 this->writeWord(rhs, out);
2143 }
2144 rhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002145 operandType = &leftType;
Ethan Nicholase6592142020-09-08 10:22:09 -04002146 } else if (rightType.typeKind() == Type::TypeKind::kVector && leftType.isNumber()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002147 if (op == Token::Kind::TK_STAR) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002148 SpvId result = this->nextId();
2149 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2150 result, rhs, lhs, out);
2151 return result;
2152 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002153 // promote number to vector
2154 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002155 const Type& vecType = rightType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002156 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2157 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002158 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002159 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002160 this->writeWord(lhs, out);
2161 }
2162 lhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002163 operandType = &rightType;
Ethan Nicholase6592142020-09-08 10:22:09 -04002164 } else if (leftType.typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002165 SpvOp_ spvop;
Ethan Nicholase6592142020-09-08 10:22:09 -04002166 if (rightType.typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002167 spvop = SpvOpMatrixTimesMatrix;
Ethan Nicholase6592142020-09-08 10:22:09 -04002168 } else if (rightType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002169 spvop = SpvOpMatrixTimesVector;
ethannicholasb3058bd2016-07-01 08:22:01 -07002170 } else {
Ethan Nicholase6592142020-09-08 10:22:09 -04002171 SkASSERT(rightType.typeKind() == Type::TypeKind::kScalar);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002172 spvop = SpvOpMatrixTimesScalar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002173 }
2174 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002175 this->writeInstruction(spvop, this->getType(resultType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002176 return result;
Ethan Nicholase6592142020-09-08 10:22:09 -04002177 } else if (rightType.typeKind() == Type::TypeKind::kMatrix) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002178 SpvId result = this->nextId();
Ethan Nicholase6592142020-09-08 10:22:09 -04002179 if (leftType.typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002180 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(resultType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002181 lhs, rhs, out);
2182 } else {
Ethan Nicholase6592142020-09-08 10:22:09 -04002183 SkASSERT(leftType.typeKind() == Type::TypeKind::kScalar);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002184 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(resultType), result,
2185 rhs, lhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002186 }
2187 return result;
2188 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002189 SkASSERT(false);
2190 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002191 }
2192 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002193 tmp = this->getActualType(leftType);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002194 operandType = &tmp;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002195 SkASSERT(*operandType == this->getActualType(rightType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002196 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002197 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002198 case Token::Kind::TK_EQEQ: {
Ethan Nicholase6592142020-09-08 10:22:09 -04002199 if (operandType->typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002200 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002201 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002202 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002203 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002204 const Type* tmpType;
Ethan Nicholase6592142020-09-08 10:22:09 -04002205 if (operandType->typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002206 tmpType = &fContext.fBool_Type->toCompound(fContext,
2207 operandType->columns(),
2208 operandType->rows());
2209 } else {
2210 tmpType = &resultType;
2211 }
2212 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002213 SpvOpFOrdEqual, SpvOpIEqual,
2214 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002215 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002216 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002217 case Token::Kind::TK_NEQ:
Ethan Nicholase6592142020-09-08 10:22:09 -04002218 if (operandType->typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002219 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002220 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002221 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002222 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002223 const Type* tmpType;
Ethan Nicholase6592142020-09-08 10:22:09 -04002224 if (operandType->typeKind() == Type::TypeKind::kVector) {
Ethan Nicholas48e24052018-03-14 13:51:39 -04002225 tmpType = &fContext.fBool_Type->toCompound(fContext,
2226 operandType->columns(),
2227 operandType->rows());
2228 } else {
2229 tmpType = &resultType;
2230 }
2231 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002232 SpvOpFOrdNotEqual, SpvOpINotEqual,
2233 SpvOpINotEqual, SpvOpLogicalNotEqual,
2234 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002235 *operandType, SpvOpAny, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002236 case Token::Kind::TK_GT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002237 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002238 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2239 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002240 SpvOpUGreaterThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002241 case Token::Kind::TK_LT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002242 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002243 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002244 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002245 case Token::Kind::TK_GTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002246 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002247 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2248 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002249 SpvOpUGreaterThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002250 case Token::Kind::TK_LTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002251 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002252 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2253 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002254 SpvOpULessThanEqual, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002255 case Token::Kind::TK_PLUS:
Ethan Nicholase6592142020-09-08 10:22:09 -04002256 if (leftType.typeKind() == Type::TypeKind::kMatrix &&
2257 rightType.typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002258 SkASSERT(leftType == rightType);
2259 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002260 SpvOpFAdd, SpvOpIAdd, out);
2261 }
Greg Daniel64773e62016-11-22 09:44:03 -05002262 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002263 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002264 case Token::Kind::TK_MINUS:
Ethan Nicholase6592142020-09-08 10:22:09 -04002265 if (leftType.typeKind() == Type::TypeKind::kMatrix &&
2266 rightType.typeKind() == Type::TypeKind::kMatrix) {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002267 SkASSERT(leftType == rightType);
2268 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002269 SpvOpFSub, SpvOpISub, out);
2270 }
Greg Daniel64773e62016-11-22 09:44:03 -05002271 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002272 SpvOpISub, SpvOpISub, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002273 case Token::Kind::TK_STAR:
Ethan Nicholase6592142020-09-08 10:22:09 -04002274 if (leftType.typeKind() == Type::TypeKind::kMatrix &&
2275 rightType.typeKind() == Type::TypeKind::kMatrix) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002276 // matrix multiply
2277 SpvId result = this->nextId();
2278 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2279 lhs, rhs, out);
2280 return result;
2281 }
Greg Daniel64773e62016-11-22 09:44:03 -05002282 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002283 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002284 case Token::Kind::TK_SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002285 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002286 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002287 case Token::Kind::TK_PERCENT:
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002288 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2289 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002290 case Token::Kind::TK_SHL:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002291 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2292 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2293 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002294 case Token::Kind::TK_SHR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002295 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2296 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2297 SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002298 case Token::Kind::TK_BITWISEAND:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002299 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2300 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002301 case Token::Kind::TK_BITWISEOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002302 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2303 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002304 case Token::Kind::TK_BITWISEXOR:
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002305 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2306 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002307 case Token::Kind::TK_COMMA:
Ethan Nicholas5a9a9b82019-09-20 12:59:22 -04002308 return rhs;
ethannicholasb3058bd2016-07-01 08:22:01 -07002309 default:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002310 SkASSERT(false);
2311 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002312 }
2313}
2314
Ethan Nicholas49465b42019-04-17 12:22:21 -04002315SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002316 const Expression& left = b.left();
2317 const Expression& right = b.right();
2318 Token::Kind op = b.getOperator();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002319 // handle cases where we don't necessarily evaluate both LHS and RHS
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002320 switch (op) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002321 case Token::Kind::TK_EQ: {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002322 SpvId rhs = this->writeExpression(right, out);
2323 this->getLValue(left, out)->store(rhs, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002324 return rhs;
2325 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002326 case Token::Kind::TK_LOGICALAND:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002327 return this->writeLogicalAnd(b, out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002328 case Token::Kind::TK_LOGICALOR:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002329 return this->writeLogicalOr(b, out);
2330 default:
2331 break;
2332 }
2333
2334 std::unique_ptr<LValue> lvalue;
2335 SpvId lhs;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002336 if (Compiler::IsAssignment(op)) {
2337 lvalue = this->getLValue(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002338 lhs = lvalue->load(out);
2339 } else {
2340 lvalue = nullptr;
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002341 lhs = this->writeExpression(left, out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002342 }
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002343 SpvId rhs = this->writeExpression(right, out);
2344 SpvId result = this->writeBinaryExpression(left.type(), lhs, Compiler::RemoveAssignment(op),
2345 right.type(), rhs, b.type(), out);
Ethan Nicholas49465b42019-04-17 12:22:21 -04002346 if (lvalue) {
2347 lvalue->store(result, out);
2348 }
2349 return result;
2350}
2351
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002352SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002353 SkASSERT(a.getOperator() == Token::Kind::TK_LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002354 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002355 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002356 SpvId lhs = this->writeExpression(a.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002357 SpvId rhsLabel = this->nextId();
2358 SpvId end = this->nextId();
2359 SpvId lhsBlock = fCurrentBlock;
2360 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2361 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2362 this->writeLabel(rhsLabel, out);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002363 SpvId rhs = this->writeExpression(a.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002364 SpvId rhsBlock = fCurrentBlock;
2365 this->writeInstruction(SpvOpBranch, end, out);
2366 this->writeLabel(end, out);
2367 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002368 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002369 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002370 return result;
2371}
2372
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002373SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002374 SkASSERT(o.getOperator() == Token::Kind::TK_LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002375 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002376 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002377 SpvId lhs = this->writeExpression(o.left(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002378 SpvId rhsLabel = this->nextId();
2379 SpvId end = this->nextId();
2380 SpvId lhsBlock = fCurrentBlock;
2381 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2382 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2383 this->writeLabel(rhsLabel, out);
Ethan Nicholasc8d9c8e2020-09-22 15:05:37 -04002384 SpvId rhs = this->writeExpression(o.right(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002385 SpvId rhsBlock = fCurrentBlock;
2386 this->writeInstruction(SpvOpBranch, end, out);
2387 this->writeLabel(end, out);
2388 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002389 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002390 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002391 return result;
2392}
2393
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002394SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002395 const Type& type = t.type();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002396 SpvId test = this->writeExpression(*t.test(), out);
2397 if (t.ifTrue()->type().columns() == 1 &&
2398 t.ifTrue()->isCompileTimeConstant() &&
2399 t.ifFalse()->isCompileTimeConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002400 // both true and false are constants, can just use OpSelect
2401 SpvId result = this->nextId();
Ethan Nicholasdd218162020-10-08 05:48:01 -04002402 SpvId trueId = this->writeExpression(*t.ifTrue(), out);
2403 SpvId falseId = this->writeExpression(*t.ifFalse(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002404 this->writeInstruction(SpvOpSelect, this->getType(type), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002405 out);
2406 return result;
2407 }
Greg Daniel64773e62016-11-22 09:44:03 -05002408 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002409 // Adreno. Switched to storing the result in a temp variable as glslang does.
2410 SpvId var = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002411 this->writeInstruction(SpvOpVariable, this->getPointerType(type, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002412 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002413 SpvId trueLabel = this->nextId();
2414 SpvId falseLabel = this->nextId();
2415 SpvId end = this->nextId();
2416 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2417 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2418 this->writeLabel(trueLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002419 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifTrue(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002420 this->writeInstruction(SpvOpBranch, end, out);
2421 this->writeLabel(falseLabel, out);
Ethan Nicholasdd218162020-10-08 05:48:01 -04002422 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.ifFalse(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002423 this->writeInstruction(SpvOpBranch, end, out);
2424 this->writeLabel(end, out);
2425 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002426 this->writeInstruction(SpvOpLoad, this->getType(type), result, var, out);
2427 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002428 return result;
2429}
2430
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002431SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002432 const Type& type = p.type();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002433 if (p.getOperator() == Token::Kind::TK_MINUS) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002434 SpvId result = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002435 SpvId typeId = this->getType(type);
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002436 SpvId expr = this->writeExpression(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002437 if (is_float(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002438 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002439 } else if (is_signed(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002440 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2441 } else {
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002442#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002443 ABORT("unsupported prefix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002444#endif
Brian Salomon23356442018-11-30 15:33:19 -05002445 }
Ethan Nicholas30d30222020-09-11 12:27:26 -04002446 this->writePrecisionModifier(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002447 return result;
2448 }
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002449 switch (p.getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002450 case Token::Kind::TK_PLUS:
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002451 return this->writeExpression(*p.operand(), out);
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002452 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002453 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002454 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
2455 SpvId result = this->writeBinaryOperation(type, type, lv->load(out), one,
Greg Daniel64773e62016-11-22 09:44:03 -05002456 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002457 out);
2458 lv->store(result, out);
2459 return result;
2460 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002461 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002462 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002463 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
2464 SpvId result = this->writeBinaryOperation(type, type, lv->load(out), one, SpvOpFSub,
2465 SpvOpISub, SpvOpISub, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002466 lv->store(result, out);
2467 return result;
2468 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002469 case Token::Kind::TK_LOGICALNOT: {
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002470 SkASSERT(p.operand()->type() == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002471 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002472 this->writeInstruction(SpvOpLogicalNot, this->getType(type), result,
2473 this->writeExpression(*p.operand(), out), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002474 return result;
2475 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002476 case Token::Kind::TK_BITWISENOT: {
ethannicholas5961bc92016-10-12 06:39:56 -07002477 SpvId result = this->nextId();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002478 this->writeInstruction(SpvOpNot, this->getType(type), result,
2479 this->writeExpression(*p.operand(), out), out);
ethannicholas5961bc92016-10-12 06:39:56 -07002480 return result;
2481 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002482 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002483#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002484 ABORT("unsupported prefix expression: %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002485#endif
2486 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002487 }
2488}
2489
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002490SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002491 const Type& type = p.type();
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002492 std::unique_ptr<LValue> lv = this->getLValue(*p.operand(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002493 SpvId result = lv->load(out);
Ethan Nicholas30d30222020-09-11 12:27:26 -04002494 SpvId one = this->writeExpression(*create_literal_1(fContext, type), out);
Ethan Nicholas444ccc62020-10-09 10:16:22 -04002495 switch (p.getOperator()) {
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002496 case Token::Kind::TK_PLUSPLUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002497 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002498 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2499 lv->store(temp, out);
2500 return result;
2501 }
Ethan Nicholas5a9e7fb2020-04-17 12:45:51 -04002502 case Token::Kind::TK_MINUSMINUS: {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002503 SpvId temp = this->writeBinaryOperation(type, type, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002504 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2505 lv->store(temp, out);
2506 return result;
2507 }
2508 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002509#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002510 ABORT("unsupported postfix expression %s", p.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002511#endif
2512 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002513 }
2514}
2515
ethannicholasf789b382016-08-03 12:43:36 -07002516SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
Ethan Nicholas59d660c2020-09-28 09:18:15 -04002517 if (b.value()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002518 if (fBoolTrue == 0) {
2519 fBoolTrue = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002520 this->writeInstruction(SpvOpConstantTrue, this->getType(b.type()), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002521 fConstantBuffer);
2522 }
2523 return fBoolTrue;
2524 } else {
2525 if (fBoolFalse == 0) {
2526 fBoolFalse = this->nextId();
Ethan Nicholas30d30222020-09-11 12:27:26 -04002527 this->writeInstruction(SpvOpConstantFalse, this->getType(b.type()), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002528 fConstantBuffer);
2529 }
2530 return fBoolFalse;
2531 }
2532}
2533
ethannicholasf789b382016-08-03 12:43:36 -07002534SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002535 const Type& type = i.type();
2536 ConstantType constantType;
2537 if (type == *fContext.fInt_Type) {
2538 constantType = ConstantType::kInt;
2539 } else if (type == *fContext.fUInt_Type) {
2540 constantType = ConstantType::kUInt;
2541 } else if (type == *fContext.fShort_Type || type == *fContext.fByte_Type) {
2542 constantType = ConstantType::kShort;
2543 } else if (type == *fContext.fUShort_Type || type == *fContext.fUByte_Type) {
2544 constantType = ConstantType::kUShort;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002545 } else {
2546 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002547 }
Ethan Nicholase96cdd12020-09-28 16:27:18 -04002548 std::pair<ConstantValue, ConstantType> key(i.value(), constantType);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002549 auto entry = fNumberConstants.find(key);
2550 if (entry == fNumberConstants.end()) {
2551 SpvId result = this->nextId();
Ethan Nicholase96cdd12020-09-28 16:27:18 -04002552 this->writeInstruction(SpvOpConstant, this->getType(type), result, (SpvId) i.value(),
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002553 fConstantBuffer);
2554 fNumberConstants[key] = result;
2555 return result;
2556 }
2557 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002558}
2559
ethannicholasf789b382016-08-03 12:43:36 -07002560SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002561 const Type& type = f.type();
2562 ConstantType constantType;
2563 if (type == *fContext.fHalf_Type) {
2564 constantType = ConstantType::kHalf;
ethannicholasb3058bd2016-07-01 08:22:01 -07002565 } else {
Ethan Nicholas30d30222020-09-11 12:27:26 -04002566 constantType = ConstantType::kFloat;
ethannicholasb3058bd2016-07-01 08:22:01 -07002567 }
Ethan Nicholasa3f22f12020-10-01 12:13:17 -04002568 float value = (float) f.value();
2569 std::pair<ConstantValue, ConstantType> key(f.value(), constantType);
John Stiles8c578662020-06-01 15:32:47 +00002570 auto entry = fNumberConstants.find(key);
2571 if (entry == fNumberConstants.end()) {
2572 SpvId result = this->nextId();
2573 uint32_t bits;
2574 SkASSERT(sizeof(bits) == sizeof(value));
2575 memcpy(&bits, &value, sizeof(bits));
Ethan Nicholas30d30222020-09-11 12:27:26 -04002576 this->writeInstruction(SpvOpConstant, this->getType(type), result, bits,
John Stiles8c578662020-06-01 15:32:47 +00002577 fConstantBuffer);
2578 fNumberConstants[key] = result;
2579 return result;
2580 }
2581 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002582}
2583
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002584SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002585 SpvId result = fFunctionMap[&f];
Ethan Nicholased84b732020-10-08 11:45:44 -04002586 this->writeInstruction(SpvOpFunction, this->getType(f.returnType()), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002587 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04002588 this->writeInstruction(SpvOpName, result, f.name(), fNameBuffer);
Brian Osman5bf3e202020-10-13 10:34:18 -04002589 const std::vector<const Variable*>& parameters = f.parameters();
Ethan Nicholased84b732020-10-08 11:45:44 -04002590 for (size_t i = 0; i < parameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002591 SpvId id = this->nextId();
Ethan Nicholased84b732020-10-08 11:45:44 -04002592 fVariableMap[parameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002593 SpvId type;
Ethan Nicholased84b732020-10-08 11:45:44 -04002594 type = this->getPointerType(parameters[i]->type(), SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002595 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2596 }
2597 return result;
2598}
2599
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002600SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2601 fVariableBuffer.reset();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002602 SpvId result = this->writeFunctionStart(f.declaration(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002603 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002604 StringStream bodyBuffer;
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002605 this->writeBlock((Block&) *f.body(), bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002606 write_stringstream(fVariableBuffer, out);
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002607 if (f.declaration().name() == "main") {
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002608 write_stringstream(fGlobalInitializersBuffer, out);
2609 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002610 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002611 if (fCurrentBlock) {
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04002612 if (f.declaration().returnType() == *fContext.fVoid_Type) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002613 this->writeInstruction(SpvOpReturn, out);
2614 } else {
2615 this->writeInstruction(SpvOpUnreachable, out);
2616 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002617 }
2618 this->writeInstruction(SpvOpFunctionEnd, out);
2619 return result;
2620}
2621
2622void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2623 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002624 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002625 fDecorationBuffer);
2626 }
2627 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002628 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002629 fDecorationBuffer);
2630 }
2631 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002632 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002633 fDecorationBuffer);
2634 }
2635 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002636 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002637 fDecorationBuffer);
2638 }
Greg Daniel64773e62016-11-22 09:44:03 -05002639 if (layout.fInputAttachmentIndex >= 0) {
2640 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2641 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002642 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002643 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002644 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002645 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002646 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002647 fDecorationBuffer);
2648 }
2649}
2650
2651void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2652 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002653 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002654 layout.fLocation, fDecorationBuffer);
2655 }
2656 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002657 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002658 layout.fBinding, fDecorationBuffer);
2659 }
2660 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002661 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002662 layout.fIndex, fDecorationBuffer);
2663 }
2664 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002665 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002666 layout.fSet, fDecorationBuffer);
2667 }
Greg Daniel64773e62016-11-22 09:44:03 -05002668 if (layout.fInputAttachmentIndex >= 0) {
2669 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2670 layout.fInputAttachmentIndex, fDecorationBuffer);
2671 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002672 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002673 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002674 layout.fBuiltin, fDecorationBuffer);
2675 }
2676}
2677
Ethan Nicholas81d15112018-07-13 12:48:50 -04002678static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2679 switch (m.fLayout.fPrimitive) {
2680 case Layout::kPoints_Primitive:
2681 *outSkInCount = 1;
2682 break;
2683 case Layout::kLines_Primitive:
2684 *outSkInCount = 2;
2685 break;
2686 case Layout::kLinesAdjacency_Primitive:
2687 *outSkInCount = 4;
2688 break;
2689 case Layout::kTriangles_Primitive:
2690 *outSkInCount = 3;
2691 break;
2692 case Layout::kTrianglesAdjacency_Primitive:
2693 *outSkInCount = 6;
2694 break;
2695 default:
2696 return;
2697 }
2698}
2699
Stephen White88574972020-06-23 19:09:29 -04002700SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf, bool appendRTHeight) {
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002701 bool isBuffer = ((intf.variable().modifiers().fFlags & Modifiers::kBuffer_Flag) != 0);
2702 bool pushConstant = ((intf.variable().modifiers().fLayout.fFlags &
2703 Layout::kPushConstant_Flag) != 0);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002704 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2705 MemoryLayout(MemoryLayout::k430_Standard) :
2706 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002707 SpvId result = this->nextId();
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002708 const Type* type = &intf.variable().type();
Stephen White88574972020-06-23 19:09:29 -04002709 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Greg Daniele6ab9982018-08-22 13:56:32 +00002710 SkASSERT(fRTHeightStructId == (SpvId) -1);
2711 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002712 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002713 fRTHeightStructId = result;
2714 fRTHeightFieldIndex = fields.size();
2715 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002716 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002717 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002718 SpvId typeId;
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002719 Modifiers intfModifiers = intf.variable().modifiers();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002720 if (intfModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osman1179fcf2020-10-08 16:04:40 -04002721 for (const auto& e : fProgram.elements()) {
2722 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04002723 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholas81d15112018-07-13 12:48:50 -04002724 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002725 }
2726 }
Ethan Nicholase6592142020-09-08 10:22:09 -04002727 typeId = this->getType(Type("sk_in", Type::TypeKind::kArray,
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002728 intf.variable().type().componentType(),
Ethan Nicholase6592142020-09-08 10:22:09 -04002729 fSkInCount),
2730 memoryLayout);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002731 } else {
2732 typeId = this->getType(*type, memoryLayout);
2733 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002734 if (intfModifiers.fFlags & Modifiers::kBuffer_Flag) {
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002735 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002736 } else if (intfModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002737 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002738 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002739 SpvStorageClass_ storageClass = get_storage_class(intfModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002740 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002741 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002742 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002743 Layout layout = intfModifiers.fLayout;
2744 if (intfModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002745 layout.fSet = 0;
2746 }
2747 this->writeLayout(layout, result);
Ethan Nicholaseaf47882020-10-15 10:10:08 -04002748 fVariableMap[&intf.variable()] = result;
Stephen White88574972020-06-23 19:09:29 -04002749 if (fProgram.fInputs.fRTHeight && appendRTHeight) {
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002750 delete type;
2751 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002752 return result;
2753}
2754
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002755void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002756 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2757}
2758
2759void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2760 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002761 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2762 }
2763}
2764
Chris Dalton2284aab2019-11-15 11:02:24 -07002765bool is_dead(const Variable& var) {
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002766 if (var.readCount() || var.writeCount()) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002767 return false;
2768 }
2769 // not entirely sure what the rules are for when it's safe to elide interface variables, but it
2770 // causes various problems to elide some of them even when dead. But it also causes problems
2771 // *not* to elide sk_SampleMask when it's not being used.
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002772 if (!(var.modifiers().fFlags & (Modifiers::kIn_Flag |
2773 Modifiers::kOut_Flag |
2774 Modifiers::kUniform_Flag |
2775 Modifiers::kBuffer_Flag))) {
Chris Dalton2284aab2019-11-15 11:02:24 -07002776 return true;
2777 }
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002778 return var.modifiers().fLayout.fBuiltin == SK_SAMPLEMASK_BUILTIN;
Chris Dalton2284aab2019-11-15 11:02:24 -07002779}
2780
ethannicholas5961bc92016-10-12 06:39:56 -07002781#define BUILTIN_IGNORE 9999
Brian Osmanc0213602020-10-06 14:43:32 -04002782void SPIRVCodeGenerator::writeGlobalVar(Program::Kind kind, const VarDeclaration& varDecl,
2783 OutputStream& out) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002784 const Variable& var = varDecl.var();
Brian Osmanc0213602020-10-06 14:43:32 -04002785 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2786 // in the OpenGL backend.
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002787 SkASSERT(!(var.modifiers().fFlags & (Modifiers::kReadOnly_Flag |
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04002788 Modifiers::kWriteOnly_Flag |
2789 Modifiers::kCoherent_Flag |
2790 Modifiers::kVolatile_Flag |
2791 Modifiers::kRestrict_Flag)));
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002792 if (var.modifiers().fLayout.fBuiltin == BUILTIN_IGNORE) {
Brian Osmanc0213602020-10-06 14:43:32 -04002793 return;
2794 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002795 if (var.modifiers().fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
Brian Osmanc0213602020-10-06 14:43:32 -04002796 kind != Program::kFragment_Kind) {
2797 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
2798 return;
2799 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002800 if (is_dead(var)) {
Brian Osmanc0213602020-10-06 14:43:32 -04002801 return;
2802 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002803 const Type& type = var.type();
Brian Osmanc0213602020-10-06 14:43:32 -04002804 SpvStorageClass_ storageClass;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002805 if (var.modifiers().fFlags & Modifiers::kIn_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002806 storageClass = SpvStorageClassInput;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002807 } else if (var.modifiers().fFlags & Modifiers::kOut_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002808 storageClass = SpvStorageClassOutput;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002809 } else if (var.modifiers().fFlags & Modifiers::kUniform_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002810 if (type.typeKind() == Type::TypeKind::kSampler ||
2811 type.typeKind() == Type::TypeKind::kSeparateSampler ||
2812 type.typeKind() == Type::TypeKind::kTexture) {
2813 storageClass = SpvStorageClassUniformConstant;
ethannicholasb3058bd2016-07-01 08:22:01 -07002814 } else {
Brian Osmanc0213602020-10-06 14:43:32 -04002815 storageClass = SpvStorageClassUniform;
ethannicholasb3058bd2016-07-01 08:22:01 -07002816 }
Brian Osmanc0213602020-10-06 14:43:32 -04002817 } else {
2818 storageClass = SpvStorageClassPrivate;
2819 }
2820 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002821 fVariableMap[&var] = id;
Brian Osmanc0213602020-10-06 14:43:32 -04002822 SpvId typeId;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002823 if (var.modifiers().fLayout.fBuiltin == SK_IN_BUILTIN) {
Brian Osmanc0213602020-10-06 14:43:32 -04002824 typeId = this->getPointerType(
2825 Type("sk_in", Type::TypeKind::kArray, type.componentType(), fSkInCount),
2826 storageClass);
2827 } else {
2828 typeId = this->getPointerType(type, storageClass);
2829 }
2830 this->writeInstruction(SpvOpVariable, typeId, id, storageClass, fConstantBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002831 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002832 this->writePrecisionModifier(type, id);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002833 if (varDecl.value()) {
Brian Osmanc0213602020-10-06 14:43:32 -04002834 SkASSERT(!fCurrentBlock);
2835 fCurrentBlock = -1;
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002836 SpvId value = this->writeExpression(*varDecl.value(), fGlobalInitializersBuffer);
Brian Osmanc0213602020-10-06 14:43:32 -04002837 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
2838 fCurrentBlock = 0;
2839 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002840 this->writeLayout(var.modifiers().fLayout, id);
2841 if (var.modifiers().fFlags & Modifiers::kFlat_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002842 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2843 }
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002844 if (var.modifiers().fFlags & Modifiers::kNoPerspective_Flag) {
Brian Osmanc0213602020-10-06 14:43:32 -04002845 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2846 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002847 }
2848}
2849
Brian Osmanc0213602020-10-06 14:43:32 -04002850void SPIRVCodeGenerator::writeVarDeclaration(const VarDeclaration& varDecl, OutputStream& out) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002851 const Variable& var = varDecl.var();
Brian Osmanc0213602020-10-06 14:43:32 -04002852 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2853 // in the OpenGL backend.
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002854 SkASSERT(!(var.modifiers().fFlags & (Modifiers::kReadOnly_Flag |
2855 Modifiers::kWriteOnly_Flag |
2856 Modifiers::kCoherent_Flag |
2857 Modifiers::kVolatile_Flag |
2858 Modifiers::kRestrict_Flag)));
Brian Osmanc0213602020-10-06 14:43:32 -04002859 SpvId id = this->nextId();
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002860 fVariableMap[&var] = id;
2861 SpvId type = this->getPointerType(var.type(), SpvStorageClassFunction);
Brian Osmanc0213602020-10-06 14:43:32 -04002862 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04002863 this->writeInstruction(SpvOpName, id, var.name(), fNameBuffer);
2864 if (varDecl.value()) {
2865 SpvId value = this->writeExpression(*varDecl.value(), out);
Brian Osmanc0213602020-10-06 14:43:32 -04002866 this->writeInstruction(SpvOpStore, id, value, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002867 }
2868}
2869
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002870void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
Ethan Nicholase6592142020-09-08 10:22:09 -04002871 switch (s.kind()) {
John Stiles98c1f822020-09-09 14:18:53 -04002872 case Statement::Kind::kInlineMarker:
Ethan Nicholase6592142020-09-08 10:22:09 -04002873 case Statement::Kind::kNop:
Ethan Nicholascb670962017-04-20 19:31:52 -04002874 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002875 case Statement::Kind::kBlock:
ethannicholasb3058bd2016-07-01 08:22:01 -07002876 this->writeBlock((Block&) s, out);
2877 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002878 case Statement::Kind::kExpression:
Ethan Nicholasd503a5a2020-09-30 09:29:55 -04002879 this->writeExpression(*s.as<ExpressionStatement>().expression(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002880 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002881 case Statement::Kind::kReturn:
John Stiles26f98502020-08-18 09:30:51 -04002882 this->writeReturnStatement(s.as<ReturnStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002883 break;
Brian Osmanc0213602020-10-06 14:43:32 -04002884 case Statement::Kind::kVarDeclaration:
2885 this->writeVarDeclaration(s.as<VarDeclaration>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002886 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002887 case Statement::Kind::kIf:
John Stiles26f98502020-08-18 09:30:51 -04002888 this->writeIfStatement(s.as<IfStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002889 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002890 case Statement::Kind::kFor:
John Stiles26f98502020-08-18 09:30:51 -04002891 this->writeForStatement(s.as<ForStatement>(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002892 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002893 case Statement::Kind::kWhile:
John Stiles26f98502020-08-18 09:30:51 -04002894 this->writeWhileStatement(s.as<WhileStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002895 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002896 case Statement::Kind::kDo:
John Stiles26f98502020-08-18 09:30:51 -04002897 this->writeDoStatement(s.as<DoStatement>(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002898 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002899 case Statement::Kind::kSwitch:
John Stiles26f98502020-08-18 09:30:51 -04002900 this->writeSwitchStatement(s.as<SwitchStatement>(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002901 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002902 case Statement::Kind::kBreak:
ethannicholasb3058bd2016-07-01 08:22:01 -07002903 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2904 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002905 case Statement::Kind::kContinue:
ethannicholasb3058bd2016-07-01 08:22:01 -07002906 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2907 break;
Ethan Nicholase6592142020-09-08 10:22:09 -04002908 case Statement::Kind::kDiscard:
ethannicholasb3058bd2016-07-01 08:22:01 -07002909 this->writeInstruction(SpvOpKill, out);
2910 break;
2911 default:
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002912#ifdef SK_DEBUG
ethannicholasb3058bd2016-07-01 08:22:01 -07002913 ABORT("unsupported statement: %s", s.description().c_str());
Ethan Nicholas2a099da2020-01-02 14:40:54 -05002914#endif
2915 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002916 }
2917}
2918
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002919void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
Ethan Nicholas7bd60432020-09-25 14:31:59 -04002920 for (const std::unique_ptr<Statement>& stmt : b.children()) {
2921 this->writeStatement(*stmt, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002922 }
2923}
2924
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002925void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002926 SpvId test = this->writeExpression(*stmt.test(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002927 SpvId ifTrue = this->nextId();
2928 SpvId ifFalse = this->nextId();
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002929 if (stmt.ifFalse()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002930 SpvId end = this->nextId();
2931 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2932 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2933 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002934 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002935 if (fCurrentBlock) {
2936 this->writeInstruction(SpvOpBranch, end, out);
2937 }
2938 this->writeLabel(ifFalse, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002939 this->writeStatement(*stmt.ifFalse(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002940 if (fCurrentBlock) {
2941 this->writeInstruction(SpvOpBranch, end, out);
2942 }
2943 this->writeLabel(end, out);
2944 } else {
2945 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2946 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2947 this->writeLabel(ifTrue, out);
Ethan Nicholas8c44eca2020-10-07 16:47:09 -04002948 this->writeStatement(*stmt.ifTrue(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002949 if (fCurrentBlock) {
2950 this->writeInstruction(SpvOpBranch, ifFalse, out);
2951 }
2952 this->writeLabel(ifFalse, out);
2953 }
2954}
2955
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002956void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04002957 if (f.initializer()) {
2958 this->writeStatement(*f.initializer(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002959 }
2960 SpvId header = this->nextId();
2961 SpvId start = this->nextId();
2962 SpvId body = this->nextId();
2963 SpvId next = this->nextId();
2964 fContinueTarget.push(next);
2965 SpvId end = this->nextId();
2966 fBreakTarget.push(end);
2967 this->writeInstruction(SpvOpBranch, header, out);
2968 this->writeLabel(header, out);
2969 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002970 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002971 this->writeLabel(start, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04002972 if (f.test()) {
2973 SpvId test = this->writeExpression(*f.test(), out);
ethannicholas22f939e2016-10-13 13:25:34 -07002974 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2975 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002976 this->writeLabel(body, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04002977 this->writeStatement(*f.statement(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002978 if (fCurrentBlock) {
2979 this->writeInstruction(SpvOpBranch, next, out);
2980 }
2981 this->writeLabel(next, out);
Ethan Nicholas0d31ed52020-10-05 14:47:09 -04002982 if (f.next()) {
2983 this->writeExpression(*f.next(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002984 }
2985 this->writeInstruction(SpvOpBranch, header, out);
2986 this->writeLabel(end, out);
2987 fBreakTarget.pop();
2988 fContinueTarget.pop();
2989}
2990
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002991void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002992 SpvId header = this->nextId();
2993 SpvId start = this->nextId();
2994 SpvId body = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04002995 SpvId continueTarget = this->nextId();
2996 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002997 SpvId end = this->nextId();
2998 fBreakTarget.push(end);
2999 this->writeInstruction(SpvOpBranch, header, out);
3000 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003001 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003002 this->writeInstruction(SpvOpBranch, start, out);
3003 this->writeLabel(start, out);
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003004 SpvId test = this->writeExpression(*w.test(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003005 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
3006 this->writeLabel(body, out);
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003007 this->writeStatement(*w.statement(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003008 if (fCurrentBlock) {
Ethan Nicholas0d997662019-04-08 09:46:01 -04003009 this->writeInstruction(SpvOpBranch, continueTarget, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003010 }
Ethan Nicholas0d997662019-04-08 09:46:01 -04003011 this->writeLabel(continueTarget, out);
3012 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003013 this->writeLabel(end, out);
3014 fBreakTarget.pop();
3015 fContinueTarget.pop();
3016}
3017
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003018void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003019 SpvId header = this->nextId();
3020 SpvId start = this->nextId();
3021 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003022 SpvId continueTarget = this->nextId();
3023 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003024 SpvId end = this->nextId();
3025 fBreakTarget.push(end);
3026 this->writeInstruction(SpvOpBranch, header, out);
3027 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003028 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003029 this->writeInstruction(SpvOpBranch, start, out);
3030 this->writeLabel(start, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003031 this->writeStatement(*d.statement(), out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003032 if (fCurrentBlock) {
3033 this->writeInstruction(SpvOpBranch, next, out);
3034 }
3035 this->writeLabel(next, out);
Ethan Nicholas1fd61162020-09-28 13:14:19 -04003036 SpvId test = this->writeExpression(*d.test(), out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003037 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
3038 this->writeLabel(continueTarget, out);
3039 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003040 this->writeLabel(end, out);
3041 fBreakTarget.pop();
3042 fContinueTarget.pop();
3043}
3044
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003045void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
3046 SpvId value = this->writeExpression(*s.fValue, out);
3047 std::vector<SpvId> labels;
3048 SpvId end = this->nextId();
3049 SpvId defaultLabel = end;
3050 fBreakTarget.push(end);
3051 int size = 3;
3052 for (const auto& c : s.fCases) {
3053 SpvId label = this->nextId();
3054 labels.push_back(label);
3055 if (c->fValue) {
3056 size += 2;
3057 } else {
3058 defaultLabel = label;
3059 }
3060 }
3061 labels.push_back(end);
3062 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3063 this->writeOpCode(SpvOpSwitch, size, out);
3064 this->writeWord(value, out);
3065 this->writeWord(defaultLabel, out);
3066 for (size_t i = 0; i < s.fCases.size(); ++i) {
3067 if (!s.fCases[i]->fValue) {
3068 continue;
3069 }
Ethan Nicholase96cdd12020-09-28 16:27:18 -04003070 this->writeWord(s.fCases[i]->fValue->as<IntLiteral>().value(), out);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003071 this->writeWord(labels[i], out);
3072 }
3073 for (size_t i = 0; i < s.fCases.size(); ++i) {
3074 this->writeLabel(labels[i], out);
3075 for (const auto& stmt : s.fCases[i]->fStatements) {
3076 this->writeStatement(*stmt, out);
3077 }
3078 if (fCurrentBlock) {
3079 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3080 }
3081 }
3082 this->writeLabel(end, out);
3083 fBreakTarget.pop();
3084}
3085
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003086void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
Ethan Nicholas2a4952d2020-10-08 15:35:56 -04003087 if (r.expression()) {
3088 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.expression(), out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003089 out);
3090 } else {
3091 this->writeInstruction(SpvOpReturn, out);
3092 }
3093}
3094
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003095void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003096 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003097 int invocations = 1;
Brian Osman1179fcf2020-10-08 16:04:40 -04003098 for (const auto& e : fProgram.elements()) {
3099 if (e->is<ModifiersDeclaration>()) {
Ethan Nicholas077050b2020-10-13 10:30:20 -04003100 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003101 if (m.fFlags & Modifiers::kIn_Flag) {
3102 if (m.fLayout.fInvocations != -1) {
3103 invocations = m.fLayout.fInvocations;
3104 }
3105 SpvId input;
3106 switch (m.fLayout.fPrimitive) {
3107 case Layout::kPoints_Primitive:
3108 input = SpvExecutionModeInputPoints;
3109 break;
3110 case Layout::kLines_Primitive:
3111 input = SpvExecutionModeInputLines;
3112 break;
3113 case Layout::kLinesAdjacency_Primitive:
3114 input = SpvExecutionModeInputLinesAdjacency;
3115 break;
3116 case Layout::kTriangles_Primitive:
3117 input = SpvExecutionModeTriangles;
3118 break;
3119 case Layout::kTrianglesAdjacency_Primitive:
3120 input = SpvExecutionModeInputTrianglesAdjacency;
3121 break;
3122 default:
3123 input = 0;
3124 break;
3125 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003126 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003127 if (input) {
3128 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3129 }
3130 } else if (m.fFlags & Modifiers::kOut_Flag) {
3131 SpvId output;
3132 switch (m.fLayout.fPrimitive) {
3133 case Layout::kPoints_Primitive:
3134 output = SpvExecutionModeOutputPoints;
3135 break;
3136 case Layout::kLineStrip_Primitive:
3137 output = SpvExecutionModeOutputLineStrip;
3138 break;
3139 case Layout::kTriangleStrip_Primitive:
3140 output = SpvExecutionModeOutputTriangleStrip;
3141 break;
3142 default:
3143 output = 0;
3144 break;
3145 }
3146 if (output) {
3147 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3148 }
3149 if (m.fLayout.fMaxVertices != -1) {
3150 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3151 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3152 out);
3153 }
3154 }
3155 }
3156 }
3157 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3158 invocations, out);
3159}
3160
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003161void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003162 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003163 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003164 std::set<SpvId> interfaceVars;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003165 // assign IDs to functions, determine sk_in size
3166 int skInSize = -1;
Brian Osman1179fcf2020-10-08 16:04:40 -04003167 for (const auto& e : program.elements()) {
3168 switch (e->kind()) {
Ethan Nicholase6592142020-09-08 10:22:09 -04003169 case ProgramElement::Kind::kFunction: {
Brian Osman1179fcf2020-10-08 16:04:40 -04003170 const FunctionDefinition& f = e->as<FunctionDefinition>();
Ethan Nicholas0a5d0962020-10-14 13:33:18 -04003171 fFunctionMap[&f.declaration()] = this->nextId();
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003172 break;
3173 }
Ethan Nicholase6592142020-09-08 10:22:09 -04003174 case ProgramElement::Kind::kModifiers: {
Ethan Nicholas077050b2020-10-13 10:30:20 -04003175 const Modifiers& m = e->as<ModifiersDeclaration>().modifiers();
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003176 if (m.fFlags & Modifiers::kIn_Flag) {
3177 switch (m.fLayout.fPrimitive) {
3178 case Layout::kPoints_Primitive: // break
3179 case Layout::kLines_Primitive:
3180 skInSize = 1;
3181 break;
3182 case Layout::kLinesAdjacency_Primitive: // break
3183 skInSize = 2;
3184 break;
3185 case Layout::kTriangles_Primitive: // break
3186 case Layout::kTrianglesAdjacency_Primitive:
3187 skInSize = 3;
3188 break;
3189 default:
3190 break;
3191 }
3192 }
3193 break;
3194 }
3195 default:
3196 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003197 }
3198 }
Brian Osman1179fcf2020-10-08 16:04:40 -04003199 for (const auto& e : program.elements()) {
3200 if (e->is<InterfaceBlock>()) {
3201 InterfaceBlock& intf = e->as<InterfaceBlock>();
Ethan Nicholaseaf47882020-10-15 10:10:08 -04003202 const Modifiers& modifiers = intf.variable().modifiers();
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003203 if (SK_IN_BUILTIN == modifiers.fLayout.fBuiltin) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003204 SkASSERT(skInSize != -1);
Ethan Nicholaseaf47882020-10-15 10:10:08 -04003205 intf.sizes().emplace_back(new IntLiteral(fContext, -1, skInSize));
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003206 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003207 SpvId id = this->writeInterfaceBlock(intf);
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003208 if (((modifiers.fFlags & Modifiers::kIn_Flag) ||
3209 (modifiers.fFlags & Modifiers::kOut_Flag)) &&
3210 modifiers.fLayout.fBuiltin == -1 &&
Ethan Nicholaseaf47882020-10-15 10:10:08 -04003211 !is_dead(intf.variable())) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003212 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003213 }
3214 }
3215 }
Brian Osman1179fcf2020-10-08 16:04:40 -04003216 for (const auto& e : program.elements()) {
3217 if (e->is<GlobalVarDeclaration>()) {
Ethan Nicholasc51f33e2020-10-13 13:49:44 -04003218 this->writeGlobalVar(program.fKind,
3219 e->as<GlobalVarDeclaration>().declaration()->as<VarDeclaration>(),
3220 body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003221 }
3222 }
Brian Osman1179fcf2020-10-08 16:04:40 -04003223 for (const auto& e : program.elements()) {
3224 if (e->is<FunctionDefinition>()) {
3225 this->writeFunction(e->as<FunctionDefinition>(), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003226 }
3227 }
ethannicholasd598f792016-07-25 10:08:54 -07003228 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003229 for (auto entry : fFunctionMap) {
Ethan Nicholase2c49992020-10-05 11:49:11 -04003230 if (entry.first->name() == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003231 main = entry.first;
3232 }
3233 }
Ethan Nicholas1a668d22019-04-18 10:37:40 -04003234 if (!main) {
3235 fErrors.error(0, "program does not contain a main() function");
3236 return;
3237 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003238 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003239 const Variable* var = entry.first;
Ethan Nicholas453f67f2020-10-09 10:43:45 -04003240 if (var->storage() == Variable::Storage::kGlobal &&
Ethan Nicholas041fd0a2020-10-07 16:42:04 -04003241 ((var->modifiers().fFlags & Modifiers::kIn_Flag) ||
3242 (var->modifiers().fFlags & Modifiers::kOut_Flag)) && !is_dead(*var)) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003243 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003244 }
3245 }
3246 this->writeCapabilities(out);
3247 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3248 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003249 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->name().fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003250 (int32_t) interfaceVars.size(), out);
3251 switch (program.fKind) {
3252 case Program::kVertex_Kind:
3253 this->writeWord(SpvExecutionModelVertex, out);
3254 break;
3255 case Program::kFragment_Kind:
3256 this->writeWord(SpvExecutionModelFragment, out);
3257 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003258 case Program::kGeometry_Kind:
3259 this->writeWord(SpvExecutionModelGeometry, out);
3260 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003261 default:
3262 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003263 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003264 SpvId entryPoint = fFunctionMap[main];
3265 this->writeWord(entryPoint, out);
Ethan Nicholase2c49992020-10-05 11:49:11 -04003266 this->writeString(main->name().fChars, main->name().fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003267 for (int var : interfaceVars) {
3268 this->writeWord(var, out);
3269 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003270 if (program.fKind == Program::kGeometry_Kind) {
3271 this->writeGeometryShaderExecutionMode(entryPoint, out);
3272 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003273 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003274 this->writeInstruction(SpvOpExecutionMode,
3275 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003276 SpvExecutionModeOriginUpperLeft,
3277 out);
3278 }
Brian Osman1179fcf2020-10-08 16:04:40 -04003279 for (const auto& e : program.elements()) {
3280 if (e->is<Extension>()) {
3281 this->writeInstruction(SpvOpSourceExtension, e->as<Extension>().name().c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003282 }
3283 }
Greg Daniel64773e62016-11-22 09:44:03 -05003284
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003285 write_stringstream(fExtraGlobalsBuffer, out);
3286 write_stringstream(fNameBuffer, out);
3287 write_stringstream(fDecorationBuffer, out);
3288 write_stringstream(fConstantBuffer, out);
3289 write_stringstream(fExternalFunctionsBuffer, out);
3290 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003291}
3292
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003293bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003294 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003295 this->writeWord(SpvMagicNumber, *fOut);
3296 this->writeWord(SpvVersion, *fOut);
3297 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003298 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003299 this->writeInstructions(fProgram, buffer);
3300 this->writeWord(fIdCount, *fOut);
3301 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003302 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003303 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003304}
3305
John Stilesa6841be2020-08-06 14:11:56 -04003306} // namespace SkSL