blob: 34728d5304af584cd8ee35a3ab09ad696b21ba0a [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);
Ethan Nicholasffdc3e62019-09-19 16:58:33 -0400144 fIntrinsicMap[String("unpremul")] = SPECIAL(Unpremul);
ethannicholasb3058bd2016-07-01 08:22:01 -0700145// interpolateAt* not yet supported...
146}
147
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400148void SPIRVCodeGenerator::writeWord(int32_t word, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700149 out.write((const char*) &word, sizeof(word));
ethannicholasb3058bd2016-07-01 08:22:01 -0700150}
151
ethannicholasd598f792016-07-25 10:08:54 -0700152static bool is_float(const Context& context, const Type& type) {
Ethan Nicholas0df21132018-07-10 09:37:51 -0400153 if (type.columns() > 1) {
ethannicholasd598f792016-07-25 10:08:54 -0700154 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700155 }
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400156 return type == *context.fFloat_Type || type == *context.fHalf_Type ||
157 type == *context.fDouble_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700158}
159
ethannicholasd598f792016-07-25 10:08:54 -0700160static bool is_signed(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700161 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700162 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700163 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400164 return type == *context.fInt_Type || type == *context.fShort_Type ||
165 type == *context.fByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700166}
167
ethannicholasd598f792016-07-25 10:08:54 -0700168static bool is_unsigned(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700169 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700170 return is_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700171 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400172 return type == *context.fUInt_Type || type == *context.fUShort_Type ||
173 type == *context.fUByte_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700174}
175
ethannicholasd598f792016-07-25 10:08:54 -0700176static bool is_bool(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700177 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700178 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700179 }
ethannicholasd598f792016-07-25 10:08:54 -0700180 return type == *context.fBool_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700181}
182
ethannicholasd598f792016-07-25 10:08:54 -0700183static bool is_out(const Variable& var) {
184 return (var.fModifiers.fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700185}
186
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400187void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400188 SkASSERT(opCode != SpvOpLoad || &out != &fConstantBuffer);
189 SkASSERT(opCode != SpvOpUndef);
ethannicholasb3058bd2016-07-01 08:22:01 -0700190 switch (opCode) {
191 case SpvOpReturn: // fall through
192 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700193 case SpvOpKill: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700194 case SpvOpBranch: // fall through
195 case SpvOpBranchConditional:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400196 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700197 fCurrentBlock = 0;
198 break;
199 case SpvOpConstant: // fall through
200 case SpvOpConstantTrue: // fall through
201 case SpvOpConstantFalse: // fall through
202 case SpvOpConstantComposite: // fall through
203 case SpvOpTypeVoid: // fall through
204 case SpvOpTypeInt: // fall through
205 case SpvOpTypeFloat: // fall through
206 case SpvOpTypeBool: // fall through
207 case SpvOpTypeVector: // fall through
208 case SpvOpTypeMatrix: // fall through
209 case SpvOpTypeArray: // fall through
210 case SpvOpTypePointer: // fall through
211 case SpvOpTypeFunction: // fall through
212 case SpvOpTypeRuntimeArray: // fall through
213 case SpvOpTypeStruct: // fall through
214 case SpvOpTypeImage: // fall through
215 case SpvOpTypeSampledImage: // fall through
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400216 case SpvOpTypeSampler: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700217 case SpvOpVariable: // fall through
218 case SpvOpFunction: // fall through
219 case SpvOpFunctionParameter: // fall through
220 case SpvOpFunctionEnd: // fall through
221 case SpvOpExecutionMode: // fall through
222 case SpvOpMemoryModel: // fall through
223 case SpvOpCapability: // fall through
224 case SpvOpExtInstImport: // fall through
225 case SpvOpEntryPoint: // fall through
226 case SpvOpSource: // fall through
227 case SpvOpSourceExtension: // fall through
228 case SpvOpName: // fall through
229 case SpvOpMemberName: // fall through
230 case SpvOpDecorate: // fall through
231 case SpvOpMemberDecorate:
232 break;
233 default:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400234 SkASSERT(fCurrentBlock);
ethannicholasb3058bd2016-07-01 08:22:01 -0700235 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700236 this->writeWord((length << 16) | opCode, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700237}
238
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400239void SPIRVCodeGenerator::writeLabel(SpvId label, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700240 fCurrentBlock = label;
241 this->writeInstruction(SpvOpLabel, label, out);
242}
243
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400244void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700245 this->writeOpCode(opCode, 1, out);
246}
247
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400248void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700249 this->writeOpCode(opCode, 2, out);
250 this->writeWord(word1, out);
251}
252
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700253void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputStream& out) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400254 out.write(string, length);
ethannicholasb3058bd2016-07-01 08:22:01 -0700255 switch (length % 4) {
256 case 1:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500257 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700258 // fall through
259 case 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500260 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700261 // fall through
262 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500263 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700264 break;
265 default:
266 this->writeWord(0, out);
267 }
268}
269
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700270void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, StringFragment string, OutputStream& out) {
271 this->writeOpCode(opCode, 1 + (string.fLength + 4) / 4, out);
272 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700273}
274
275
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700276void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, StringFragment string,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400277 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700278 this->writeOpCode(opCode, 2 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700279 this->writeWord(word1, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700280 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700281}
282
Greg Daniel64773e62016-11-22 09:44:03 -0500283void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700284 StringFragment string, OutputStream& out) {
285 this->writeOpCode(opCode, 3 + (string.fLength + 4) / 4, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700286 this->writeWord(word1, out);
287 this->writeWord(word2, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700288 this->writeString(string.fChars, string.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700289}
290
Greg Daniel64773e62016-11-22 09:44:03 -0500291void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400292 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700293 this->writeOpCode(opCode, 3, out);
294 this->writeWord(word1, out);
295 this->writeWord(word2, out);
296}
297
Greg Daniel64773e62016-11-22 09:44:03 -0500298void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400299 int32_t word3, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700300 this->writeOpCode(opCode, 4, out);
301 this->writeWord(word1, out);
302 this->writeWord(word2, out);
303 this->writeWord(word3, out);
304}
305
Greg Daniel64773e62016-11-22 09:44:03 -0500306void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400307 int32_t word3, int32_t word4, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700308 this->writeOpCode(opCode, 5, out);
309 this->writeWord(word1, out);
310 this->writeWord(word2, out);
311 this->writeWord(word3, out);
312 this->writeWord(word4, out);
313}
314
Greg Daniel64773e62016-11-22 09:44:03 -0500315void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
316 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400317 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700318 this->writeOpCode(opCode, 6, out);
319 this->writeWord(word1, out);
320 this->writeWord(word2, out);
321 this->writeWord(word3, out);
322 this->writeWord(word4, out);
323 this->writeWord(word5, out);
324}
325
Greg Daniel64773e62016-11-22 09:44:03 -0500326void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700327 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400328 int32_t word6, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700329 this->writeOpCode(opCode, 7, out);
330 this->writeWord(word1, out);
331 this->writeWord(word2, out);
332 this->writeWord(word3, out);
333 this->writeWord(word4, out);
334 this->writeWord(word5, out);
335 this->writeWord(word6, out);
336}
337
Greg Daniel64773e62016-11-22 09:44:03 -0500338void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700339 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400340 int32_t word6, int32_t word7, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700341 this->writeOpCode(opCode, 8, out);
342 this->writeWord(word1, out);
343 this->writeWord(word2, out);
344 this->writeWord(word3, out);
345 this->writeWord(word4, out);
346 this->writeWord(word5, out);
347 this->writeWord(word6, out);
348 this->writeWord(word7, out);
349}
350
Greg Daniel64773e62016-11-22 09:44:03 -0500351void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700352 int32_t word3, int32_t word4, int32_t word5,
353 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400354 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700355 this->writeOpCode(opCode, 9, out);
356 this->writeWord(word1, out);
357 this->writeWord(word2, out);
358 this->writeWord(word3, out);
359 this->writeWord(word4, out);
360 this->writeWord(word5, out);
361 this->writeWord(word6, out);
362 this->writeWord(word7, out);
363 this->writeWord(word8, out);
364}
365
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400366void SPIRVCodeGenerator::writeCapabilities(OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700367 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
368 if (fCapabilities & bit) {
369 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
370 }
371 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400372 if (fProgram.fKind == Program::kGeometry_Kind) {
373 this->writeInstruction(SpvOpCapability, SpvCapabilityGeometry, out);
374 }
Ethan Nicholas81d15112018-07-13 12:48:50 -0400375 else {
376 this->writeInstruction(SpvOpCapability, SpvCapabilityShader, out);
377 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700378}
379
380SpvId SPIRVCodeGenerator::nextId() {
381 return fIdCount++;
382}
383
Ethan Nicholas19671772016-11-28 16:30:17 -0500384void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
385 SpvId resultId) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700386 this->writeInstruction(SpvOpName, resultId, type.name().c_str(), fNameBuffer);
387 // go ahead and write all of the field types, so we don't inadvertently write them while we're
388 // in the middle of writing the struct instruction
389 std::vector<SpvId> types;
390 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500391 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700392 }
393 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
394 this->writeWord(resultId, fConstantBuffer);
395 for (SpvId id : types) {
396 this->writeWord(id, fConstantBuffer);
397 }
398 size_t offset = 0;
399 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400400 const Type::Field& field = type.fields()[i];
401 size_t size = memoryLayout.size(*field.fType);
402 size_t alignment = memoryLayout.alignment(*field.fType);
403 const Layout& fieldLayout = field.fModifiers.fLayout;
Ethan Nicholas19671772016-11-28 16:30:17 -0500404 if (fieldLayout.fOffset >= 0) {
Greg Danieldbd44c72017-01-24 15:12:12 -0500405 if (fieldLayout.fOffset < (int) offset) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700406 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400407 "offset of field '" + field.fName + "' must be at "
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500408 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -0500409 }
410 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700411 fErrors.error(type.fOffset,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400412 "offset of field '" + field.fName + "' must be a multiple"
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500413 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -0500414 }
415 offset = fieldLayout.fOffset;
416 } else {
417 size_t mod = offset % alignment;
418 if (mod) {
419 offset += alignment - mod;
420 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700421 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400422 this->writeInstruction(SpvOpMemberName, resultId, i, field.fName, fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -0500423 this->writeLayout(fieldLayout, resultId, i);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400424 if (field.fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -0500425 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -0700426 (SpvId) offset, fDecorationBuffer);
427 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400428 if (field.fType->kind() == Type::kMatrix_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -0500429 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -0700430 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500431 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400432 (SpvId) memoryLayout.stride(*field.fType),
ethannicholas8ac838d2016-11-22 08:39:36 -0800433 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700434 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400435 if (!field.fType->highPrecision()) {
436 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i,
437 SpvDecorationRelaxedPrecision, fDecorationBuffer);
438 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700439 offset += size;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400440 Type::Kind kind = field.fType->kind();
ethannicholasb3058bd2016-07-01 08:22:01 -0700441 if ((kind == Type::kArray_Kind || kind == Type::kStruct_Kind) && offset % alignment != 0) {
442 offset += alignment - offset % alignment;
443 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700444 }
445}
446
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400447Type SPIRVCodeGenerator::getActualType(const Type& type) {
Ethan Nicholase1f55022019-02-05 17:17:40 -0500448 if (type.isFloat()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400449 return *fContext.fFloat_Type;
450 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500451 if (type.isSigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400452 return *fContext.fInt_Type;
453 }
Ethan Nicholase1f55022019-02-05 17:17:40 -0500454 if (type.isUnsigned()) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400455 return *fContext.fUInt_Type;
456 }
457 if (type.kind() == Type::kMatrix_Kind || type.kind() == Type::kVector_Kind) {
458 if (type.componentType() == *fContext.fHalf_Type) {
459 return fContext.fFloat_Type->toCompound(fContext, type.columns(), type.rows());
460 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400461 if (type.componentType() == *fContext.fShort_Type ||
462 type.componentType() == *fContext.fByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400463 return fContext.fInt_Type->toCompound(fContext, type.columns(), type.rows());
464 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -0400465 if (type.componentType() == *fContext.fUShort_Type ||
466 type.componentType() == *fContext.fUByte_Type) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400467 return fContext.fUInt_Type->toCompound(fContext, type.columns(), type.rows());
468 }
469 }
470 return type;
471}
472
ethannicholasb3058bd2016-07-01 08:22:01 -0700473SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -0800474 return this->getType(type, fDefaultLayout);
475}
476
Ethan Nicholasf7b88202017-09-18 14:10:39 -0400477SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layout) {
478 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400479 String key = type.name() + to_string((int) layout.fStd);
ethannicholas8ac838d2016-11-22 08:39:36 -0800480 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -0700481 if (entry == fTypeMap.end()) {
482 SpvId result = this->nextId();
483 switch (type.kind()) {
484 case Type::kScalar_Kind:
ethannicholasd598f792016-07-25 10:08:54 -0700485 if (type == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700486 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500487 } else if (type == *fContext.fInt_Type || type == *fContext.fShort_Type ||
488 type == *fContext.fIntLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700489 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500490 } else if (type == *fContext.fUInt_Type || type == *fContext.fUShort_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700491 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
Ethan Nicholase1f55022019-02-05 17:17:40 -0500492 } else if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type ||
493 type == *fContext.fFloatLiteral_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700494 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -0700495 } else if (type == *fContext.fDouble_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700496 this->writeInstruction(SpvOpTypeFloat, result, 64, fConstantBuffer);
497 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400498 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -0700499 }
500 break;
501 case Type::kVector_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500502 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800503 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700504 type.columns(), fConstantBuffer);
505 break;
506 case Type::kMatrix_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -0500507 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800508 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700509 type.columns(), fConstantBuffer);
510 break;
511 case Type::kStruct_Kind:
ethannicholas8ac838d2016-11-22 08:39:36 -0800512 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -0700513 break;
514 case Type::kArray_Kind: {
515 if (type.columns() > 0) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700516 IntLiteral count(fContext, -1, type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -0500517 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800518 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -0700519 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -0500520 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400521 (int32_t) layout.stride(type),
ethannicholas8ac838d2016-11-22 08:39:36 -0800522 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700523 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400524 SkASSERT(false); // we shouldn't have any runtime-sized arrays right now
Greg Daniel64773e62016-11-22 09:44:03 -0500525 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -0800526 this->getType(type.componentType(), layout),
527 fConstantBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -0400528 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
529 (int32_t) layout.stride(type),
530 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -0700531 }
532 break;
533 }
534 case Type::kSampler_Kind: {
Greg Daniel64773e62016-11-22 09:44:03 -0500535 SpvId image = result;
536 if (SpvDimSubpassData != type.dimensions()) {
Stephen White792e2302019-08-09 13:33:51 -0400537 image = this->getType(type.textureType(), layout);
Greg Daniel64773e62016-11-22 09:44:03 -0500538 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400539 if (SpvDimBuffer == type.dimensions()) {
540 fCapabilities |= (((uint64_t) 1) << SpvCapabilitySampledBuffer);
541 }
Greg Daniel64773e62016-11-22 09:44:03 -0500542 if (SpvDimSubpassData != type.dimensions()) {
543 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
544 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700545 break;
546 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400547 case Type::kSeparateSampler_Kind: {
548 this->writeInstruction(SpvOpTypeSampler, result, fConstantBuffer);
549 break;
550 }
551 case Type::kTexture_Kind: {
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400552 this->writeInstruction(SpvOpTypeImage, result,
553 this->getType(*fContext.fFloat_Type, layout),
Stephen White792e2302019-08-09 13:33:51 -0400554 type.dimensions(), type.isDepth(), type.isArrayed(),
555 type.isMultisampled(), type.isSampled() ? 1 : 2,
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400556 SpvImageFormatUnknown, fConstantBuffer);
557 fImageTypeMap[key] = result;
558 break;
559 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700560 default:
ethannicholasd598f792016-07-25 10:08:54 -0700561 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700562 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
563 } else {
564 ABORT("invalid type: %s", type.description().c_str());
565 }
566 }
ethannicholas8ac838d2016-11-22 08:39:36 -0800567 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -0700568 return result;
569 }
570 return entry->second;
571}
572
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400573SpvId SPIRVCodeGenerator::getImageType(const Type& type) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400574 SkASSERT(type.kind() == Type::kSampler_Kind);
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400575 this->getType(type);
576 String key = type.name() + to_string((int) fDefaultLayout.fStd);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400577 SkASSERT(fImageTypeMap.find(key) != fImageTypeMap.end());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400578 return fImageTypeMap[key];
579}
580
ethannicholasd598f792016-07-25 10:08:54 -0700581SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400582 String key = function.fReturnType.description() + "(";
583 String separator;
ethannicholasd598f792016-07-25 10:08:54 -0700584 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700585 key += separator;
586 separator = ", ";
ethannicholasd598f792016-07-25 10:08:54 -0700587 key += function.fParameters[i]->fType.description();
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();
ethannicholasd598f792016-07-25 10:08:54 -0700593 int32_t length = 3 + (int32_t) function.fParameters.size();
594 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700595 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -0700596 for (size_t i = 0; i < function.fParameters.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])) {
ethannicholasd598f792016-07-25 10:08:54 -0700620 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
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 Nicholasf7b88202017-09-18 14:10:39 -0400644 Type type = this->getActualType(rawType);
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400645 String key = type.description() + "*" + 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) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700658 switch (expr.fKind) {
659 case Expression::kBinary_Kind:
660 return this->writeBinaryExpression((BinaryExpression&) expr, out);
661 case Expression::kBoolLiteral_Kind:
662 return this->writeBoolLiteral((BoolLiteral&) expr);
663 case Expression::kConstructor_Kind:
664 return this->writeConstructor((Constructor&) expr, out);
665 case Expression::kIntLiteral_Kind:
666 return this->writeIntLiteral((IntLiteral&) expr);
667 case Expression::kFieldAccess_Kind:
668 return this->writeFieldAccess(((FieldAccess&) expr), out);
669 case Expression::kFloatLiteral_Kind:
670 return this->writeFloatLiteral(((FloatLiteral&) expr));
671 case Expression::kFunctionCall_Kind:
672 return this->writeFunctionCall((FunctionCall&) expr, out);
673 case Expression::kPrefix_Kind:
674 return this->writePrefixExpression((PrefixExpression&) expr, out);
675 case Expression::kPostfix_Kind:
676 return this->writePostfixExpression((PostfixExpression&) expr, out);
677 case Expression::kSwizzle_Kind:
678 return this->writeSwizzle((Swizzle&) expr, out);
679 case Expression::kVariableReference_Kind:
680 return this->writeVariableReference((VariableReference&) expr, out);
681 case Expression::kTernary_Kind:
682 return this->writeTernaryExpression((TernaryExpression&) expr, out);
683 case Expression::kIndex_Kind:
684 return this->writeIndexExpression((IndexExpression&) expr, out);
685 default:
686 ABORT("unsupported expression: %s", expr.description().c_str());
687 }
688 return -1;
689}
690
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400691SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -0700692 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400693 SkASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -0700694 int32_t intrinsicId;
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400695 if (c.fArguments.size() > 0) {
696 const Type& type = c.fArguments[0]->fType;
697 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
698 intrinsicId = std::get<1>(intrinsic->second);
699 } else if (is_signed(fContext, type)) {
700 intrinsicId = std::get<2>(intrinsic->second);
701 } else if (is_unsigned(fContext, type)) {
702 intrinsicId = std::get<3>(intrinsic->second);
703 } else if (is_bool(fContext, type)) {
704 intrinsicId = std::get<4>(intrinsic->second);
705 } else {
706 intrinsicId = std::get<1>(intrinsic->second);
707 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700708 } else {
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400709 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasb3058bd2016-07-01 08:22:01 -0700710 }
711 switch (std::get<0>(intrinsic->second)) {
712 case kGLSL_STD_450_IntrinsicKind: {
713 SpvId result = this->nextId();
714 std::vector<SpvId> arguments;
715 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400716 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
717 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
718 } else {
719 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
720 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700721 }
722 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700723 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700724 this->writeWord(result, out);
725 this->writeWord(fGLSLExtendedInstructions, out);
726 this->writeWord(intrinsicId, out);
727 for (SpvId id : arguments) {
728 this->writeWord(id, out);
729 }
730 return result;
731 }
732 case kSPIRV_IntrinsicKind: {
733 SpvId result = this->nextId();
734 std::vector<SpvId> arguments;
735 for (size_t i = 0; i < c.fArguments.size(); i++) {
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -0400736 if (c.fFunction.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) {
737 arguments.push_back(this->getLValue(*c.fArguments[i], out)->getPointer());
738 } else {
739 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
740 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700741 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -0400742 if (c.fType != *fContext.fVoid_Type) {
743 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
744 this->writeWord(this->getType(c.fType), out);
745 this->writeWord(result, out);
746 } else {
747 this->writeOpCode((SpvOp_) intrinsicId, 1 + (int32_t) arguments.size(), out);
748 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700749 for (SpvId id : arguments) {
750 this->writeWord(id, out);
751 }
752 return result;
753 }
754 case kSpecial_IntrinsicKind:
755 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
756 default:
757 ABORT("unsupported intrinsic kind");
758 }
759}
760
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500761std::vector<SpvId> SPIRVCodeGenerator::vectorize(
762 const std::vector<std::unique_ptr<Expression>>& args,
763 OutputStream& out) {
764 int vectorSize = 0;
765 for (const auto& a : args) {
766 if (a->fType.kind() == Type::kVector_Kind) {
767 if (vectorSize) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400768 SkASSERT(a->fType.columns() == vectorSize);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500769 }
770 else {
771 vectorSize = a->fType.columns();
772 }
773 }
774 }
775 std::vector<SpvId> result;
776 for (const auto& a : args) {
777 SpvId raw = this->writeExpression(*a, out);
778 if (vectorSize && a->fType.kind() == Type::kScalar_Kind) {
779 SpvId vector = this->nextId();
780 this->writeOpCode(SpvOpCompositeConstruct, 3 + vectorSize, out);
781 this->writeWord(this->getType(a->fType.toCompound(fContext, vectorSize, 1)), out);
782 this->writeWord(vector, out);
783 for (int i = 0; i < vectorSize; i++) {
784 this->writeWord(raw, out);
785 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -0400786 this->writePrecisionModifier(a->fType, vector);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500787 result.push_back(vector);
788 } else {
789 result.push_back(raw);
790 }
791 }
792 return result;
793}
794
795void SPIRVCodeGenerator::writeGLSLExtendedInstruction(const Type& type, SpvId id, SpvId floatInst,
796 SpvId signedInst, SpvId unsignedInst,
797 const std::vector<SpvId>& args,
798 OutputStream& out) {
799 this->writeOpCode(SpvOpExtInst, 5 + args.size(), out);
800 this->writeWord(this->getType(type), out);
801 this->writeWord(id, out);
802 this->writeWord(fGLSLExtendedInstructions, out);
803
804 if (is_float(fContext, type)) {
805 this->writeWord(floatInst, out);
806 } else if (is_signed(fContext, type)) {
807 this->writeWord(signedInst, out);
808 } else if (is_unsigned(fContext, type)) {
809 this->writeWord(unsignedInst, out);
810 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400811 SkASSERT(false);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500812 }
813 for (SpvId a : args) {
814 this->writeWord(a, out);
815 }
816}
817
Greg Daniel64773e62016-11-22 09:44:03 -0500818SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas0df1b042017-03-31 13:56:23 -0400819 OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700820 SpvId result = this->nextId();
821 switch (kind) {
822 case kAtan_SpecialIntrinsic: {
823 std::vector<SpvId> arguments;
824 for (size_t i = 0; i < c.fArguments.size(); i++) {
825 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
826 }
827 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -0700828 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -0700829 this->writeWord(result, out);
830 this->writeWord(fGLSLExtendedInstructions, out);
831 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
832 for (SpvId id : arguments) {
833 this->writeWord(id, out);
834 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400835 break;
836 }
Stephen Whiteff5d7a22019-07-26 17:42:06 -0400837 case kSampledImage_SpecialIntrinsic: {
838 SkASSERT(2 == c.fArguments.size());
839 SpvId img = this->writeExpression(*c.fArguments[0], out);
840 SpvId sampler = this->writeExpression(*c.fArguments[1], out);
841 this->writeInstruction(SpvOpSampledImage,
842 this->getType(c.fType),
843 result,
844 img,
845 sampler,
846 out);
847 break;
848 }
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400849 case kSubpassLoad_SpecialIntrinsic: {
850 SpvId img = this->writeExpression(*c.fArguments[0], out);
851 std::vector<std::unique_ptr<Expression>> args;
Ethan Nicholas5b5f0962017-09-11 13:50:14 -0700852 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
853 args.emplace_back(new FloatLiteral(fContext, -1, 0.0));
854 Constructor ctor(-1, *fContext.fFloat2_Type, std::move(args));
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400855 SpvId coords = this->writeConstantVector(ctor);
856 if (1 == c.fArguments.size()) {
857 this->writeInstruction(SpvOpImageRead,
858 this->getType(c.fType),
859 result,
860 img,
861 coords,
862 out);
863 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400864 SkASSERT(2 == c.fArguments.size());
Ethan Nicholas0187ae62017-05-03 11:03:44 -0400865 SpvId sample = this->writeExpression(*c.fArguments[1], out);
866 this->writeInstruction(SpvOpImageRead,
867 this->getType(c.fType),
868 result,
869 img,
870 coords,
871 SpvImageOperandsSampleMask,
872 sample,
873 out);
874 }
875 break;
876 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700877 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500878 SpvOp_ op = SpvOpImageSampleImplicitLod;
879 switch (c.fArguments[0]->fType.dimensions()) {
880 case SpvDim1D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400881 if (c.fArguments[1]->fType == *fContext.fFloat2_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500882 op = SpvOpImageSampleProjImplicitLod;
883 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400884 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500885 }
886 break;
887 case SpvDim2D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400888 if (c.fArguments[1]->fType == *fContext.fFloat3_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500889 op = SpvOpImageSampleProjImplicitLod;
890 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400891 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat2_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500892 }
893 break;
894 case SpvDim3D:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -0400895 if (c.fArguments[1]->fType == *fContext.fFloat4_Type) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500896 op = SpvOpImageSampleProjImplicitLod;
897 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400898 SkASSERT(c.fArguments[1]->fType == *fContext.fFloat3_Type);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500899 }
900 break;
901 case SpvDimCube: // fall through
902 case SpvDimRect: // fall through
903 case SpvDimBuffer: // fall through
904 case SpvDimSubpassData:
905 break;
906 }
ethannicholasd598f792016-07-25 10:08:54 -0700907 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -0700908 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
909 SpvId uv = this->writeExpression(*c.fArguments[1], out);
910 if (c.fArguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -0500911 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -0700912 SpvImageOperandsBiasMask,
913 this->writeExpression(*c.fArguments[2], out),
914 out);
915 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400916 SkASSERT(c.fArguments.size() == 2);
Brian Osman8a83ca42018-02-12 14:32:17 -0500917 if (fProgram.fSettings.fSharpenTextures) {
918 FloatLiteral lodBias(fContext, -1, -0.5);
919 this->writeInstruction(op, type, result, sampler, uv,
920 SpvImageOperandsBiasMask,
921 this->writeFloatLiteral(lodBias),
922 out);
923 } else {
924 this->writeInstruction(op, type, result, sampler, uv,
925 out);
926 }
ethannicholasb3058bd2016-07-01 08:22:01 -0700927 }
928 break;
929 }
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500930 case kMod_SpecialIntrinsic: {
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500931 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400932 SkASSERT(args.size() == 2);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500933 const Type& operandType = c.fArguments[0]->fType;
934 SpvOp_ op;
935 if (is_float(fContext, operandType)) {
936 op = SpvOpFMod;
937 } else if (is_signed(fContext, operandType)) {
938 op = SpvOpSMod;
939 } else if (is_unsigned(fContext, operandType)) {
940 op = SpvOpUMod;
941 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400942 SkASSERT(false);
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500943 return 0;
944 }
945 this->writeOpCode(op, 5, out);
946 this->writeWord(this->getType(operandType), out);
947 this->writeWord(result, out);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500948 this->writeWord(args[0], out);
949 this->writeWord(args[1], out);
950 break;
951 }
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700952 case kDFdy_SpecialIntrinsic: {
953 SpvId fn = this->writeExpression(*c.fArguments[0], out);
954 this->writeOpCode(SpvOpDPdy, 4, out);
955 this->writeWord(this->getType(c.fType), out);
956 this->writeWord(result, out);
957 this->writeWord(fn, out);
958 if (fProgram.fSettings.fFlipY) {
959 // Flipping Y also negates the Y derivatives.
960 SpvId flipped = this->nextId();
961 this->writeInstruction(SpvOpFNegate, this->getType(c.fType), flipped, result, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -0400962 this->writePrecisionModifier(c.fType, flipped);
Chris Daltonb8af5ad2019-02-25 14:54:21 -0700963 return flipped;
964 }
965 break;
966 }
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500967 case kClamp_SpecialIntrinsic: {
968 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400969 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500970 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
971 GLSLstd450UClamp, args, out);
972 break;
973 }
974 case kMax_SpecialIntrinsic: {
975 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400976 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500977 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMax, GLSLstd450SMax,
978 GLSLstd450UMax, args, out);
979 break;
980 }
981 case kMin_SpecialIntrinsic: {
982 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400983 SkASSERT(args.size() == 2);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500984 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMin, GLSLstd450SMin,
985 GLSLstd450UMin, args, out);
986 break;
987 }
988 case kMix_SpecialIntrinsic: {
989 std::vector<SpvId> args = this->vectorize(c.fArguments, out);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -0400990 SkASSERT(args.size() == 3);
Ethan Nicholas0fc07f92018-02-27 15:25:47 -0500991 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FMix, SpvOpUndef,
992 SpvOpUndef, args, out);
993 break;
Ethan Nicholas70a44b22017-11-30 09:09:16 -0500994 }
Ethan Nicholas12fb9cf2018-08-03 16:16:57 -0400995 case kSaturate_SpecialIntrinsic: {
996 SkASSERT(c.fArguments.size() == 1);
997 std::vector<std::unique_ptr<Expression>> finalArgs;
998 finalArgs.push_back(c.fArguments[0]->clone());
999 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 0));
1000 finalArgs.emplace_back(new FloatLiteral(fContext, -1, 1));
1001 std::vector<SpvId> spvArgs = this->vectorize(finalArgs, out);
1002 this->writeGLSLExtendedInstruction(c.fType, result, GLSLstd450FClamp, GLSLstd450SClamp,
1003 GLSLstd450UClamp, spvArgs, out);
1004 break;
1005 }
Ethan Nicholasffdc3e62019-09-19 16:58:33 -04001006 case kUnpremul_SpecialIntrinsic: {
1007 SpvId color = this->writeExpression(*c.fArguments[0], out);
1008 SpvId a = this->writeSwizzle(*fContext.fHalf_Type, c.fArguments[0]->fType, color, { 3 },
1009 out);
1010 FloatLiteral min(fContext, -1, SKSL_UNPREMUL_MIN);
1011 SpvId minId = this->writeFloatLiteral(min);
1012 SpvId nonZeroAlpha = this->nextId();
1013 this->writeGLSLExtendedInstruction(*fContext.fHalf_Type, nonZeroAlpha, GLSLstd450FMax,
1014 SpvOpUndef, SpvOpUndef, { a, minId }, out);
1015 SpvId rgb = this->writeSwizzle(*fContext.fHalf3_Type, *fContext.fHalf4_Type, color,
1016 { 0, 1, 2 }, out);
1017 SpvId scaled = this->writeBinaryExpression(*fContext.fHalf3_Type, rgb, Token::SLASH,
1018 *fContext.fFloat_Type, nonZeroAlpha,
1019 *fContext.fHalf3_Type, out);
1020 this->writeOpCode(SpvOpCompositeConstruct, 5, out);
1021 this->writeWord(this->getType(c.fType), out);
1022 this->writeWord(result, out);
1023 this->writeWord(scaled, out);
1024 this->writeWord(nonZeroAlpha, out);
1025 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001026 }
1027 return result;
1028}
1029
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001030SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001031 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07001032 if (entry == fFunctionMap.end()) {
1033 return this->writeIntrinsicCall(c, out);
1034 }
1035 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001036 std::vector<std::tuple<SpvId, const Type*, std::unique_ptr<LValue>>> lvalues;
ethannicholasb3058bd2016-07-01 08:22:01 -07001037 std::vector<SpvId> arguments;
1038 for (size_t i = 0; i < c.fArguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001039 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001040 // passed directly
1041 SpvId tmpVar;
1042 // if we need a temporary var to store this argument, this is the value to store in the var
1043 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -07001044 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001045 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
1046 SpvId ptr = lv->getPointer();
1047 if (ptr) {
1048 arguments.push_back(ptr);
1049 continue;
1050 } else {
1051 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1052 // copy it into a temp, call the function, read the value out of the temp, and then
1053 // update the lvalue.
1054 tmpValueId = lv->load(out);
1055 tmpVar = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001056 lvalues.push_back(std::make_tuple(tmpVar, &c.fArguments[i]->fType, std::move(lv)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001057 }
1058 } else {
1059 // see getFunctionType for an explanation of why we're always using pointer parameters
1060 tmpValueId = this->writeExpression(*c.fArguments[i], out);
1061 tmpVar = this->nextId();
1062 }
Greg Daniel64773e62016-11-22 09:44:03 -05001063 this->writeInstruction(SpvOpVariable,
1064 this->getPointerType(c.fArguments[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -07001065 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001066 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001067 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001068 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001069 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1070 arguments.push_back(tmpVar);
1071 }
1072 SpvId result = this->nextId();
1073 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001074 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001075 this->writeWord(result, out);
1076 this->writeWord(entry->second, out);
1077 for (SpvId id : arguments) {
1078 this->writeWord(id, out);
1079 }
1080 // now that the call is complete, we may need to update some lvalues with the new values of out
1081 // arguments
1082 for (const auto& tuple : lvalues) {
1083 SpvId load = this->nextId();
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001084 this->writeInstruction(SpvOpLoad, getType(*std::get<1>(tuple)), load, std::get<0>(tuple),
1085 out);
1086 this->writePrecisionModifier(*std::get<1>(tuple), load);
ethannicholasb3058bd2016-07-01 08:22:01 -07001087 std::get<2>(tuple)->store(load, out);
1088 }
1089 return result;
1090}
1091
ethannicholasf789b382016-08-03 12:43:36 -07001092SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001093 SkASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001094 SpvId result = this->nextId();
1095 std::vector<SpvId> arguments;
1096 for (size_t i = 0; i < c.fArguments.size(); i++) {
1097 arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1098 }
ethannicholasd598f792016-07-25 10:08:54 -07001099 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001100 if (c.fArguments.size() == 1) {
1101 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001102 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001103 this->writeWord(type, fConstantBuffer);
1104 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001105 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001106 this->writeWord(arguments[0], fConstantBuffer);
1107 }
1108 } else {
Greg Daniel64773e62016-11-22 09:44:03 -05001109 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001110 fConstantBuffer);
1111 this->writeWord(type, fConstantBuffer);
1112 this->writeWord(result, fConstantBuffer);
1113 for (SpvId id : arguments) {
1114 this->writeWord(id, fConstantBuffer);
1115 }
1116 }
1117 return result;
1118}
1119
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001120SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001121 SkASSERT(c.fType.isFloat());
1122 SkASSERT(c.fArguments.size() == 1);
1123 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001124 SpvId result = this->nextId();
1125 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001126 if (c.fArguments[0]->fType.isSigned()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001127 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001128 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001129 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001130 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Greg Daniel64773e62016-11-22 09:44:03 -05001131 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001132 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001133 }
1134 return result;
1135}
1136
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001137SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001138 SkASSERT(c.fType.isSigned());
1139 SkASSERT(c.fArguments.size() == 1);
1140 SkASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001141 SpvId result = this->nextId();
1142 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001143 if (c.fArguments[0]->fType.isFloat()) {
Greg Daniel64773e62016-11-22 09:44:03 -05001144 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001145 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001146 }
1147 else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001148 SkASSERT(c.fArguments[0]->fType.isUnsigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001149 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), 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 Nicholasd9d33c32018-06-12 11:05:59 -04001156 SkASSERT(c.fType.isUnsigned());
1157 SkASSERT(c.fArguments.size() == 1);
1158 SkASSERT(c.fArguments[0]->fType.isNumber());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001159 SpvId result = this->nextId();
1160 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001161 if (c.fArguments[0]->fType.isFloat()) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001162 this->writeInstruction(SpvOpConvertFToU, this->getType(c.fType), result, parameter,
1163 out);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001164 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001165 SkASSERT(c.fArguments[0]->fType.isSigned());
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001166 this->writeInstruction(SpvOpBitcast, this->getType(c.fType), result, parameter,
1167 out);
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001168 }
1169 return result;
1170}
1171
Ethan Nicholas84645e32017-02-09 13:57:14 -05001172void SPIRVCodeGenerator::writeUniformScaleMatrix(SpvId id, SpvId diagonal, const Type& type,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001173 OutputStream& out) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001174 FloatLiteral zero(fContext, -1, 0);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001175 SpvId zeroId = this->writeFloatLiteral(zero);
1176 std::vector<SpvId> columnIds;
1177 for (int column = 0; column < type.columns(); column++) {
1178 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.rows(),
1179 out);
1180 this->writeWord(this->getType(type.componentType().toCompound(fContext, type.rows(), 1)),
1181 out);
1182 SpvId columnId = this->nextId();
1183 this->writeWord(columnId, out);
1184 columnIds.push_back(columnId);
1185 for (int row = 0; row < type.columns(); row++) {
1186 this->writeWord(row == column ? diagonal : zeroId, out);
1187 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001188 this->writePrecisionModifier(type, columnId);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001189 }
1190 this->writeOpCode(SpvOpCompositeConstruct, 3 + type.columns(),
1191 out);
1192 this->writeWord(this->getType(type), out);
1193 this->writeWord(id, out);
1194 for (SpvId id : columnIds) {
1195 this->writeWord(id, out);
1196 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001197 this->writePrecisionModifier(type, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001198}
1199
1200void SPIRVCodeGenerator::writeMatrixCopy(SpvId id, SpvId src, const Type& srcType,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001201 const Type& dstType, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001202 SkASSERT(srcType.kind() == Type::kMatrix_Kind);
1203 SkASSERT(dstType.kind() == Type::kMatrix_Kind);
1204 SkASSERT(srcType.componentType() == dstType.componentType());
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001205 SpvId srcColumnType = this->getType(srcType.componentType().toCompound(fContext,
1206 srcType.rows(),
1207 1));
1208 SpvId dstColumnType = this->getType(dstType.componentType().toCompound(fContext,
1209 dstType.rows(),
1210 1));
1211 SpvId zeroId;
1212 if (dstType.componentType() == *fContext.fFloat_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001213 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001214 zeroId = this->writeFloatLiteral(zero);
1215 } else if (dstType.componentType() == *fContext.fInt_Type) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001216 IntLiteral zero(fContext, -1, 0);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001217 zeroId = this->writeIntLiteral(zero);
1218 } else {
1219 ABORT("unsupported matrix component type");
1220 }
1221 SpvId zeroColumn = 0;
1222 SpvId columns[4];
1223 for (int i = 0; i < dstType.columns(); i++) {
1224 if (i < srcType.columns()) {
1225 // we're still inside the src matrix, copy the column
1226 SpvId srcColumn = this->nextId();
1227 this->writeInstruction(SpvOpCompositeExtract, srcColumnType, srcColumn, src, i, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001228 this->writePrecisionModifier(dstType, srcColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001229 SpvId dstColumn;
1230 if (srcType.rows() == dstType.rows()) {
1231 // columns are equal size, don't need to do anything
1232 dstColumn = srcColumn;
1233 }
1234 else if (dstType.rows() > srcType.rows()) {
1235 // dst column is bigger, need to zero-pad it
1236 dstColumn = this->nextId();
1237 int delta = dstType.rows() - srcType.rows();
1238 this->writeOpCode(SpvOpCompositeConstruct, 4 + delta, out);
1239 this->writeWord(dstColumnType, out);
1240 this->writeWord(dstColumn, out);
1241 this->writeWord(srcColumn, out);
1242 for (int i = 0; i < delta; ++i) {
1243 this->writeWord(zeroId, out);
1244 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001245 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001246 }
1247 else {
1248 // dst column is smaller, need to swizzle the src column
1249 dstColumn = this->nextId();
1250 int count = dstType.rows();
1251 this->writeOpCode(SpvOpVectorShuffle, 5 + count, out);
1252 this->writeWord(dstColumnType, out);
1253 this->writeWord(dstColumn, out);
1254 this->writeWord(srcColumn, out);
1255 this->writeWord(srcColumn, out);
1256 for (int i = 0; i < count; i++) {
1257 this->writeWord(i, out);
1258 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001259 this->writePrecisionModifier(dstType, dstColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001260 }
1261 columns[i] = dstColumn;
1262 } else {
1263 // we're past the end of the src matrix, need a vector of zeroes
1264 if (!zeroColumn) {
1265 zeroColumn = this->nextId();
1266 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.rows(), out);
1267 this->writeWord(dstColumnType, out);
1268 this->writeWord(zeroColumn, out);
1269 for (int i = 0; i < dstType.rows(); ++i) {
1270 this->writeWord(zeroId, out);
1271 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001272 this->writePrecisionModifier(dstType, zeroColumn);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001273 }
1274 columns[i] = zeroColumn;
1275 }
1276 }
1277 this->writeOpCode(SpvOpCompositeConstruct, 3 + dstType.columns(), out);
1278 this->writeWord(this->getType(dstType), out);
1279 this->writeWord(id, out);
1280 for (int i = 0; i < dstType.columns(); i++) {
1281 this->writeWord(columns[i], out);
1282 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001283 this->writePrecisionModifier(dstType, id);
Ethan Nicholas84645e32017-02-09 13:57:14 -05001284}
1285
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001286void SPIRVCodeGenerator::addColumnEntry(SpvId columnType, Precision precision,
1287 std::vector<SpvId>* currentColumn,
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001288 std::vector<SpvId>* columnIds,
1289 int* currentCount, int rows, SpvId entry,
1290 OutputStream& out) {
1291 SkASSERT(*currentCount < rows);
1292 ++(*currentCount);
1293 currentColumn->push_back(entry);
1294 if (*currentCount == rows) {
1295 *currentCount = 0;
1296 this->writeOpCode(SpvOpCompositeConstruct, 3 + currentColumn->size(), out);
1297 this->writeWord(columnType, out);
1298 SpvId columnId = this->nextId();
1299 this->writeWord(columnId, out);
1300 columnIds->push_back(columnId);
1301 for (SpvId id : *currentColumn) {
1302 this->writeWord(id, out);
1303 }
1304 currentColumn->clear();
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001305 this->writePrecisionModifier(precision, columnId);
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001306 }
1307}
1308
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001309SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001310 SkASSERT(c.fType.kind() == Type::kMatrix_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001311 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1312 // an instruction
1313 std::vector<SpvId> arguments;
1314 for (size_t i = 0; i < c.fArguments.size(); i++) {
1315 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1316 }
1317 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001318 int rows = c.fType.rows();
1319 int columns = c.fType.columns();
Ethan Nicholas84645e32017-02-09 13:57:14 -05001320 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1321 this->writeUniformScaleMatrix(result, arguments[0], c.fType, out);
1322 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kMatrix_Kind) {
1323 this->writeMatrixCopy(result, arguments[0], c.fArguments[0]->fType, c.fType, out);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001324 } else if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kVector_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001325 SkASSERT(c.fType.rows() == 2 && c.fType.columns() == 2);
1326 SkASSERT(c.fArguments[0]->fType.columns() == 4);
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001327 SpvId componentType = this->getType(c.fType.componentType());
1328 SpvId v[4];
1329 for (int i = 0; i < 4; ++i) {
1330 v[i] = this->nextId();
1331 this->writeInstruction(SpvOpCompositeExtract, componentType, v[i], arguments[0], i, out);
1332 }
1333 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, 2, 1));
1334 SpvId column1 = this->nextId();
1335 this->writeInstruction(SpvOpCompositeConstruct, columnType, column1, v[0], v[1], out);
1336 SpvId column2 = this->nextId();
1337 this->writeInstruction(SpvOpCompositeConstruct, columnType, column2, v[2], v[3], out);
1338 this->writeInstruction(SpvOpCompositeConstruct, this->getType(c.fType), result, column1,
1339 column2, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001340 } else {
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001341 SpvId columnType = this->getType(c.fType.componentType().toCompound(fContext, rows, 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07001342 std::vector<SpvId> columnIds;
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001343 // ids of vectors and scalars we have written to the current column so far
1344 std::vector<SpvId> currentColumn;
1345 // the total number of scalars represented by currentColumn's entries
ethannicholasb3058bd2016-07-01 08:22:01 -07001346 int currentCount = 0;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001347 Precision precision = c.fType.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001348 for (size_t i = 0; i < arguments.size(); i++) {
Ethan Nicholas5c46b722019-03-22 14:32:37 -04001349 if (currentCount == 0 && c.fArguments[i]->fType.kind() == Type::kVector_Kind &&
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001350 c.fArguments[i]->fType.columns() == c.fType.rows()) {
1351 // this is a complete column by itself
ethannicholasb3058bd2016-07-01 08:22:01 -07001352 columnIds.push_back(arguments[i]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001353 } else {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001354 if (c.fArguments[i]->fType.columns() == 1) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001355 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1356 &currentCount, rows, arguments[i], out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001357 } else {
1358 SpvId componentType = this->getType(c.fArguments[i]->fType.componentType());
Ethan Nicholas811b9442018-05-11 13:16:03 -04001359 for (int j = 0; j < c.fArguments[i]->fType.columns(); ++j) {
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001360 SpvId swizzle = this->nextId();
1361 this->writeInstruction(SpvOpCompositeExtract, componentType, swizzle,
1362 arguments[i], j, out);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001363 this->addColumnEntry(columnType, precision, &currentColumn, &columnIds,
1364 &currentCount, rows, swizzle, out);
Ethan Nicholasbe850ad2018-04-27 10:36:31 -04001365 }
1366 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001367 }
1368 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001369 SkASSERT(columnIds.size() == (size_t) columns);
ethannicholasb3058bd2016-07-01 08:22:01 -07001370 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001371 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001372 this->writeWord(result, out);
1373 for (SpvId id : columnIds) {
1374 this->writeWord(id, out);
1375 }
1376 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04001377 this->writePrecisionModifier(c.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001378 return result;
1379}
1380
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001381SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001382 SkASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001383 if (c.isConstant()) {
1384 return this->writeConstantVector(c);
1385 }
1386 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1387 // an instruction
1388 std::vector<SpvId> arguments;
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001389 for (size_t i = 0; i < c.fArguments.size(); i++) {
1390 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
1391 // SPIR-V doesn't support vector(vector-of-different-type) directly, so we need to
1392 // extract the components and convert them in that case manually. On top of that,
1393 // as of this writing there's a bug in the Intel Vulkan driver where OpCreateComposite
1394 // doesn't handle vector arguments at all, so we always extract vector components and
1395 // pass them into OpCreateComposite individually.
1396 SpvId vec = this->writeExpression(*c.fArguments[i], out);
1397 SpvOp_ op = SpvOpUndef;
1398 const Type& src = c.fArguments[i]->fType.componentType();
1399 const Type& dst = c.fType.componentType();
1400 if (dst == *fContext.fFloat_Type || dst == *fContext.fHalf_Type) {
1401 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1402 if (c.fArguments.size() == 1) {
1403 return vec;
1404 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001405 } else if (src == *fContext.fInt_Type ||
1406 src == *fContext.fShort_Type ||
1407 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001408 op = SpvOpConvertSToF;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001409 } else if (src == *fContext.fUInt_Type ||
1410 src == *fContext.fUShort_Type ||
1411 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001412 op = SpvOpConvertUToF;
1413 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001414 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001415 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001416 } else if (dst == *fContext.fInt_Type ||
1417 dst == *fContext.fShort_Type ||
1418 dst == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001419 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1420 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001421 } else if (src == *fContext.fInt_Type ||
1422 src == *fContext.fShort_Type ||
1423 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001424 if (c.fArguments.size() == 1) {
1425 return vec;
1426 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001427 } else if (src == *fContext.fUInt_Type ||
1428 src == *fContext.fUShort_Type ||
1429 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001430 op = SpvOpBitcast;
1431 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001432 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001433 }
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001434 } else if (dst == *fContext.fUInt_Type ||
1435 dst == *fContext.fUShort_Type ||
1436 dst == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001437 if (src == *fContext.fFloat_Type || src == *fContext.fHalf_Type) {
1438 op = SpvOpConvertFToS;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001439 } else if (src == *fContext.fInt_Type ||
1440 src == *fContext.fShort_Type ||
1441 src == *fContext.fByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001442 op = SpvOpBitcast;
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001443 } else if (src == *fContext.fUInt_Type ||
1444 src == *fContext.fUShort_Type ||
1445 src == *fContext.fUByte_Type) {
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001446 if (c.fArguments.size() == 1) {
1447 return vec;
1448 }
1449 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001450 SkASSERT(false);
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001451 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001452 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001453 for (int j = 0; j < c.fArguments[i]->fType.columns(); j++) {
1454 SpvId swizzle = this->nextId();
1455 this->writeInstruction(SpvOpCompositeExtract, this->getType(src), swizzle, vec, j,
1456 out);
1457 if (op != SpvOpUndef) {
1458 SpvId cast = this->nextId();
1459 this->writeInstruction(op, this->getType(dst), cast, swizzle, out);
1460 arguments.push_back(cast);
1461 } else {
1462 arguments.push_back(swizzle);
1463 }
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001464 }
Ethan Nicholas11e5bff2018-01-29 11:08:38 -05001465 } else {
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001466 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1467 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001468 }
1469 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001470 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1471 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1472 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001473 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001474 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001475 this->writeWord(arguments[0], out);
1476 }
1477 } else {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001478 SkASSERT(arguments.size() > 1);
Ethan Nicholas26a8d902018-01-29 09:25:51 -05001479 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001480 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001481 this->writeWord(result, out);
1482 for (SpvId id : arguments) {
1483 this->writeWord(id, out);
1484 }
1485 }
1486 return result;
1487}
1488
Ethan Nicholasbd553222017-07-18 15:54:59 -04001489SpvId SPIRVCodeGenerator::writeArrayConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001490 SkASSERT(c.fType.kind() == Type::kArray_Kind);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001491 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1492 // an instruction
1493 std::vector<SpvId> arguments;
1494 for (size_t i = 0; i < c.fArguments.size(); i++) {
1495 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1496 }
1497 SpvId result = this->nextId();
1498 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
1499 this->writeWord(this->getType(c.fType), out);
1500 this->writeWord(result, out);
1501 for (SpvId id : arguments) {
1502 this->writeWord(id, out);
1503 }
1504 return result;
1505}
1506
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001507SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, OutputStream& out) {
Ethan Nicholasf7b88202017-09-18 14:10:39 -04001508 if (c.fArguments.size() == 1 &&
1509 this->getActualType(c.fType) == this->getActualType(c.fArguments[0]->fType)) {
1510 return this->writeExpression(*c.fArguments[0], out);
1511 }
1512 if (c.fType == *fContext.fFloat_Type || c.fType == *fContext.fHalf_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001513 return this->writeFloatConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001514 } else if (c.fType == *fContext.fInt_Type ||
1515 c.fType == *fContext.fShort_Type ||
1516 c.fType == *fContext.fByte_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001517 return this->writeIntConstructor(c, out);
Ruiqi Maob609e6d2018-07-17 10:19:38 -04001518 } else if (c.fType == *fContext.fUInt_Type ||
1519 c.fType == *fContext.fUShort_Type ||
1520 c.fType == *fContext.fUByte_Type) {
Ethan Nicholas925f52d2017-07-19 10:42:50 -04001521 return this->writeUIntConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001522 }
ethannicholasd598f792016-07-25 10:08:54 -07001523 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001524 case Type::kVector_Kind:
1525 return this->writeVectorConstructor(c, out);
1526 case Type::kMatrix_Kind:
1527 return this->writeMatrixConstructor(c, out);
Ethan Nicholasbd553222017-07-18 15:54:59 -04001528 case Type::kArray_Kind:
1529 return this->writeArrayConstructor(c, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001530 default:
1531 ABORT("unsupported constructor: %s", c.description().c_str());
1532 }
1533}
1534
1535SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1536 if (modifiers.fFlags & Modifiers::kIn_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001537 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001538 return SpvStorageClassInput;
1539 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001540 SkASSERT(!(modifiers.fLayout.fFlags & Layout::kPushConstant_Flag));
ethannicholasb3058bd2016-07-01 08:22:01 -07001541 return SpvStorageClassOutput;
1542 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
Ethan Nicholas39204fd2017-11-27 13:12:30 -05001543 if (modifiers.fLayout.fFlags & Layout::kPushConstant_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001544 return SpvStorageClassPushConstant;
1545 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001546 return SpvStorageClassUniform;
1547 } else {
1548 return SpvStorageClassFunction;
1549 }
1550}
1551
ethannicholasf789b382016-08-03 12:43:36 -07001552SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001553 switch (expr.fKind) {
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001554 case Expression::kVariableReference_Kind: {
1555 const Variable& var = ((VariableReference&) expr).fVariable;
1556 if (var.fStorage != Variable::kGlobal_Storage) {
1557 return SpvStorageClassFunction;
1558 }
Ethan Nicholasdc0e1c32017-07-21 13:23:34 -04001559 SpvStorageClass_ result = get_storage_class(var.fModifiers);
1560 if (result == SpvStorageClassFunction) {
1561 result = SpvStorageClassPrivate;
1562 }
1563 return result;
Ethan Nicholasc6f5e102017-03-31 14:53:17 -04001564 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001565 case Expression::kFieldAccess_Kind:
1566 return get_storage_class(*((FieldAccess&) expr).fBase);
1567 case Expression::kIndex_Kind:
1568 return get_storage_class(*((IndexExpression&) expr).fBase);
1569 default:
1570 return SpvStorageClassFunction;
1571 }
1572}
1573
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001574std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001575 std::vector<SpvId> chain;
1576 switch (expr.fKind) {
1577 case Expression::kIndex_Kind: {
1578 IndexExpression& indexExpr = (IndexExpression&) expr;
1579 chain = this->getAccessChain(*indexExpr.fBase, out);
1580 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1581 break;
1582 }
1583 case Expression::kFieldAccess_Kind: {
1584 FieldAccess& fieldExpr = (FieldAccess&) expr;
1585 chain = this->getAccessChain(*fieldExpr.fBase, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001586 IntLiteral index(fContext, -1, fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001587 chain.push_back(this->writeIntLiteral(index));
1588 break;
1589 }
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001590 default: {
1591 SpvId id = this->getLValue(expr, out)->getPointer();
1592 SkASSERT(id != 0);
1593 chain.push_back(id);
1594 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001595 }
1596 return chain;
1597}
1598
1599class PointerLValue : public SPIRVCodeGenerator::LValue {
1600public:
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001601 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type,
1602 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001603 : fGen(gen)
1604 , fPointer(pointer)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001605 , fType(type)
1606 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001607
1608 virtual SpvId getPointer() override {
1609 return fPointer;
1610 }
1611
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001612 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001613 SpvId result = fGen.nextId();
1614 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001615 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001616 return result;
1617 }
1618
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001619 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001620 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1621 }
1622
1623private:
1624 SPIRVCodeGenerator& fGen;
1625 const SpvId fPointer;
1626 const SpvId fType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001627 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001628};
1629
1630class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1631public:
Greg Daniel64773e62016-11-22 09:44:03 -05001632 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001633 const Type& baseType, const Type& swizzleType,
1634 SPIRVCodeGenerator::Precision precision)
ethannicholasb3058bd2016-07-01 08:22:01 -07001635 : fGen(gen)
1636 , fVecPointer(vecPointer)
1637 , fComponents(components)
1638 , fBaseType(baseType)
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001639 , fSwizzleType(swizzleType)
1640 , fPrecision(precision) {}
ethannicholasb3058bd2016-07-01 08:22:01 -07001641
1642 virtual SpvId getPointer() override {
1643 return 0;
1644 }
1645
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001646 virtual SpvId load(OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001647 SpvId base = fGen.nextId();
1648 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001649 fGen.writePrecisionModifier(fPrecision, base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001650 SpvId result = fGen.nextId();
1651 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1652 fGen.writeWord(fGen.getType(fSwizzleType), out);
1653 fGen.writeWord(result, out);
1654 fGen.writeWord(base, out);
1655 fGen.writeWord(base, out);
1656 for (int component : fComponents) {
1657 fGen.writeWord(component, out);
1658 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001659 fGen.writePrecisionModifier(fPrecision, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001660 return result;
1661 }
1662
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001663 virtual void store(SpvId value, OutputStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001664 // use OpVectorShuffle to mix and match the vector components. We effectively create
1665 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001666 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001667 // instance, given:
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001668 // float3L = ...;
1669 // float3R = ...;
ethannicholasb3058bd2016-07-01 08:22:01 -07001670 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001671 // 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 -07001672 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1673 // (3, 1, 4).
1674 SpvId base = fGen.nextId();
1675 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1676 SpvId shuffle = fGen.nextId();
1677 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1678 fGen.writeWord(fGen.getType(fBaseType), out);
1679 fGen.writeWord(shuffle, out);
1680 fGen.writeWord(base, out);
1681 fGen.writeWord(value, out);
1682 for (int i = 0; i < fBaseType.columns(); i++) {
1683 // current offset into the virtual vector, defaults to pulling the unmodified
1684 // value from the left side
1685 int offset = i;
1686 // check to see if we are writing this component
1687 for (size_t j = 0; j < fComponents.size(); j++) {
1688 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001689 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001690 // the correct component of the right side instead of preserving the
1691 // value from the left
1692 offset = (int) (j + fBaseType.columns());
1693 break;
1694 }
1695 }
1696 fGen.writeWord(offset, out);
1697 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001698 fGen.writePrecisionModifier(fPrecision, shuffle);
ethannicholasb3058bd2016-07-01 08:22:01 -07001699 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1700 }
1701
1702private:
1703 SPIRVCodeGenerator& fGen;
1704 const SpvId fVecPointer;
1705 const std::vector<int>& fComponents;
1706 const Type& fBaseType;
1707 const Type& fSwizzleType;
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001708 const SPIRVCodeGenerator::Precision fPrecision;
ethannicholasb3058bd2016-07-01 08:22:01 -07001709};
1710
Greg Daniel64773e62016-11-22 09:44:03 -05001711std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001712 OutputStream& out) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001713 Precision precision = expr.fType.highPrecision() ? Precision::kHigh : Precision::kLow;
ethannicholasb3058bd2016-07-01 08:22:01 -07001714 switch (expr.fKind) {
1715 case Expression::kVariableReference_Kind: {
Ethan Nicholas5226b772018-05-03 16:20:41 -04001716 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07001717 const Variable& var = ((VariableReference&) expr).fVariable;
Ethan Nicholas5226b772018-05-03 16:20:41 -04001718 if (var.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
1719 type = this->getType(Type("sk_in", Type::kArray_Kind, var.fType.componentType(),
1720 fSkInCount));
1721 } else {
1722 type = this->getType(expr.fType);
1723 }
ethannicholasd598f792016-07-25 10:08:54 -07001724 auto entry = fVariableMap.find(&var);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001725 SkASSERT(entry != fVariableMap.end());
Ethan Nicholas5226b772018-05-03 16:20:41 -04001726 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(*this,
1727 entry->second,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001728 type,
1729 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001730 }
1731 case Expression::kIndex_Kind: // fall through
1732 case Expression::kFieldAccess_Kind: {
1733 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1734 SpvId member = this->nextId();
1735 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001736 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001737 this->writeWord(member, out);
1738 for (SpvId idx : chain) {
1739 this->writeWord(idx, out);
1740 }
1741 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
Ethan Nicholas8f7e28f2018-03-26 14:24:27 -04001742 *this,
1743 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001744 this->getType(expr.fType),
1745 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001746 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001747 case Expression::kSwizzle_Kind: {
1748 Swizzle& swizzle = (Swizzle&) expr;
1749 size_t count = swizzle.fComponents.size();
1750 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001751 SkASSERT(base);
ethannicholasb3058bd2016-07-01 08:22:01 -07001752 if (count == 1) {
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001753 IntLiteral index(fContext, -1, swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001754 SpvId member = this->nextId();
1755 this->writeInstruction(SpvOpAccessChain,
Greg Daniel64773e62016-11-22 09:44:03 -05001756 this->getPointerType(swizzle.fType,
1757 get_storage_class(*swizzle.fBase)),
1758 member,
1759 base,
1760 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001761 out);
1762 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1763 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001764 member,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001765 this->getType(expr.fType),
1766 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001767 } else {
1768 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
Greg Daniel64773e62016-11-22 09:44:03 -05001769 *this,
1770 base,
1771 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001772 swizzle.fBase->fType,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001773 expr.fType,
1774 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001775 }
1776 }
Ethan Nicholasa583b812018-01-18 13:32:11 -05001777 case Expression::kTernary_Kind: {
1778 TernaryExpression& t = (TernaryExpression&) expr;
1779 SpvId test = this->writeExpression(*t.fTest, out);
1780 SpvId end = this->nextId();
1781 SpvId ifTrueLabel = this->nextId();
1782 SpvId ifFalseLabel = this->nextId();
1783 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
1784 this->writeInstruction(SpvOpBranchConditional, test, ifTrueLabel, ifFalseLabel, out);
1785 this->writeLabel(ifTrueLabel, out);
1786 SpvId ifTrue = this->getLValue(*t.fIfTrue, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001787 SkASSERT(ifTrue);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001788 this->writeInstruction(SpvOpBranch, end, out);
1789 ifTrueLabel = fCurrentBlock;
1790 SpvId ifFalse = this->getLValue(*t.fIfFalse, out)->getPointer();
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001791 SkASSERT(ifFalse);
Ethan Nicholasa583b812018-01-18 13:32:11 -05001792 ifFalseLabel = fCurrentBlock;
1793 this->writeInstruction(SpvOpBranch, end, out);
1794 SpvId result = this->nextId();
1795 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, ifTrue,
1796 ifTrueLabel, ifFalse, ifFalseLabel, out);
1797 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1798 *this,
1799 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001800 this->getType(expr.fType),
1801 precision));
Ethan Nicholasa583b812018-01-18 13:32:11 -05001802 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001803 default:
1804 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001805 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001806 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1807 // caught by IRGenerator
1808 SpvId result = this->nextId();
1809 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001810 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1811 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001812 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1813 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1814 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001815 result,
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001816 this->getType(expr.fType),
1817 precision));
ethannicholasb3058bd2016-07-01 08:22:01 -07001818 }
1819}
1820
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001821SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, OutputStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001822 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001823 auto entry = fVariableMap.find(&ref.fVariable);
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04001824 SkASSERT(entry != fVariableMap.end());
ethannicholasb3058bd2016-07-01 08:22:01 -07001825 SpvId var = entry->second;
ethannicholasd598f792016-07-25 10:08:54 -07001826 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04001827 this->writePrecisionModifier(ref.fVariable.fType, result);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001828 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
1829 fProgram.fSettings.fFlipY) {
1830 // need to remap to a top-left coordinate system
Greg Daniele6ab9982018-08-22 13:56:32 +00001831 if (fRTHeightStructId == (SpvId) -1) {
1832 // height variable hasn't been written yet
1833 std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors));
1834 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
1835 std::vector<Type::Field> fields;
Ethan Nicholas0be34802019-08-15 12:36:58 -04001836 SkASSERT(fProgram.fSettings.fRTHeightOffset >= 0);
1837 fields.emplace_back(Modifiers(Layout(0, -1, fProgram.fSettings.fRTHeightOffset, -1,
1838 -1, -1, -1, -1, Layout::Format::kUnspecified,
1839 Layout::kUnspecified_Primitive, -1, -1, "",
1840 Layout::kNo_Key, Layout::CType::kDefault), 0),
1841 SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get());
Greg Daniele6ab9982018-08-22 13:56:32 +00001842 StringFragment name("sksl_synthetic_uniforms");
1843 Type intfStruct(-1, name, fields);
Ethan Nicholas0be34802019-08-15 12:36:58 -04001844 int binding;
1845 int set;
1846#ifdef SK_VULKAN
1847 const GrVkCaps* vkCaps = fProgram.fSettings.fVkCaps;
1848 SkASSERT(vkCaps);
1849 binding = vkCaps->getFragmentUniformBinding();
1850 set = vkCaps->getFragmentUniformSet();
1851#else
1852 binding = 0;
1853 set = 0;
1854#endif
1855 Layout layout(0, -1, -1, binding, -1, set, -1, -1, Layout::Format::kUnspecified,
Greg Daniele6ab9982018-08-22 13:56:32 +00001856 Layout::kUnspecified_Primitive, -1, -1, "", Layout::kNo_Key,
Ethan Nicholas78aceb22018-08-31 16:13:58 -04001857 Layout::CType::kDefault);
Ethan Nicholas91164d12019-05-15 15:29:54 -04001858 Variable* intfVar = (Variable*) fSynthetics.takeOwnership(std::unique_ptr<Symbol>(
1859 new Variable(-1,
1860 Modifiers(layout, Modifiers::kUniform_Flag),
1861 name,
1862 intfStruct,
1863 Variable::kGlobal_Storage)));
Greg Daniele6ab9982018-08-22 13:56:32 +00001864 InterfaceBlock intf(-1, intfVar, name, String(""),
1865 std::vector<std::unique_ptr<Expression>>(), st);
1866 fRTHeightStructId = this->writeInterfaceBlock(intf);
1867 fRTHeightFieldIndex = 0;
1868 }
1869 SkASSERT(fRTHeightFieldIndex != (SpvId) -1);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001870 // write float4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, gl_FragCoord.w)
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001871 SpvId xId = this->nextId();
1872 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1873 result, 0, out);
Greg Daniele6ab9982018-08-22 13:56:32 +00001874 IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex);
1875 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
1876 SpvId heightPtr = this->nextId();
1877 this->writeOpCode(SpvOpAccessChain, 5, out);
1878 this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out);
1879 this->writeWord(heightPtr, out);
1880 this->writeWord(fRTHeightStructId, out);
1881 this->writeWord(fieldIndexId, out);
1882 SpvId heightRead = this->nextId();
1883 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1884 heightPtr, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001885 SpvId rawYId = this->nextId();
1886 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1887 result, 1, out);
1888 SpvId flippedYId = this->nextId();
1889 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
Greg Daniele6ab9982018-08-22 13:56:32 +00001890 heightRead, rawYId, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001891 FloatLiteral zero(fContext, -1, 0.0);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001892 SpvId zeroId = writeFloatLiteral(zero);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07001893 FloatLiteral one(fContext, -1, 1.0);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001894 SpvId wId = this->nextId();
1895 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), wId,
1896 result, 3, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001897 SpvId flipped = this->nextId();
1898 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
Ethan Nicholas5af9ea32017-07-28 15:19:46 -04001899 this->writeWord(this->getType(*fContext.fFloat4_Type), out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001900 this->writeWord(flipped, out);
1901 this->writeWord(xId, out);
1902 this->writeWord(flippedYId, out);
1903 this->writeWord(zeroId, out);
Ethan Nicholas20798e52018-12-04 12:30:50 -05001904 this->writeWord(wId, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001905 return flipped;
1906 }
Chris Daltonb91c4662018-08-01 10:46:22 -06001907 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN &&
1908 !fProgram.fSettings.fFlipY) {
1909 // FrontFacing in Vulkan is defined in terms of a top-down render target. In skia, we use
1910 // the default convention of "counter-clockwise face is front".
1911 SpvId inverse = this->nextId();
1912 this->writeInstruction(SpvOpLogicalNot, this->getType(*fContext.fBool_Type), inverse,
1913 result, out);
1914 return inverse;
1915 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001916 return result;
1917}
1918
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001919SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, OutputStream& out) {
Ethan Nicholasa9a06902019-01-07 14:42:40 -05001920 if (expr.fBase->fType.kind() == Type::Kind::kVector_Kind) {
1921 SpvId base = this->writeExpression(*expr.fBase, out);
1922 SpvId index = this->writeExpression(*expr.fIndex, out);
1923 SpvId result = this->nextId();
1924 this->writeInstruction(SpvOpVectorExtractDynamic, this->getType(expr.fType), result, base,
1925 index, out);
1926 return result;
1927 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001928 return getLValue(expr, out)->load(out);
1929}
1930
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001931SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001932 return getLValue(f, out)->load(out);
1933}
1934
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001935SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, OutputStream& out) {
Ethan Nicholasffdc3e62019-09-19 16:58:33 -04001936 return this->writeSwizzle(swizzle.fType, swizzle.fBase->fType,
1937 this->writeExpression(*swizzle.fBase, out), swizzle.fComponents, out);
1938}
1939
1940SpvId SPIRVCodeGenerator::writeSwizzle(const Type& type, const Type& baseType, SpvId base,
1941 const std::vector<int> components, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001942 SpvId result = this->nextId();
Ethan Nicholasffdc3e62019-09-19 16:58:33 -04001943 size_t count = components.size();
ethannicholasb3058bd2016-07-01 08:22:01 -07001944 if (count == 1) {
Ethan Nicholasffdc3e62019-09-19 16:58:33 -04001945 this->writeInstruction(SpvOpCompositeExtract, this->getType(type), result, base,
1946 components[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001947 } else {
1948 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
Ethan Nicholasffdc3e62019-09-19 16:58:33 -04001949 this->writeWord(this->getType(type), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001950 this->writeWord(result, out);
1951 this->writeWord(base, out);
Ethan Nicholase455f652019-09-13 12:52:55 -04001952 SpvId other = base;
Ethan Nicholasffdc3e62019-09-19 16:58:33 -04001953 for (int c : components) {
Ethan Nicholase455f652019-09-13 12:52:55 -04001954 if (c < 0) {
1955 if (!fConstantZeroOneVector) {
1956 FloatLiteral zero(fContext, -1, 0);
1957 SpvId zeroId = this->writeFloatLiteral(zero);
1958 FloatLiteral one(fContext, -1, 1);
1959 SpvId oneId = this->writeFloatLiteral(one);
1960 SpvId type = this->getType(*fContext.fFloat2_Type);
1961 fConstantZeroOneVector = this->nextId();
1962 this->writeOpCode(SpvOpConstantComposite, 5, fConstantBuffer);
1963 this->writeWord(type, fConstantBuffer);
1964 this->writeWord(fConstantZeroOneVector, fConstantBuffer);
1965 this->writeWord(zeroId, fConstantBuffer);
1966 this->writeWord(oneId, fConstantBuffer);
1967 }
1968 other = fConstantZeroOneVector;
1969 break;
Ethan Nicholasac285b12019-02-12 16:05:18 -05001970 }
Ethan Nicholasac285b12019-02-12 16:05:18 -05001971 }
1972 this->writeWord(other, out);
Ethan Nicholasffdc3e62019-09-19 16:58:33 -04001973 for (int component : components) {
Ethan Nicholasac285b12019-02-12 16:05:18 -05001974 if (component == SKSL_SWIZZLE_0) {
Ethan Nicholasffdc3e62019-09-19 16:58:33 -04001975 this->writeWord(baseType.columns(), out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001976 } else if (component == SKSL_SWIZZLE_1) {
Ethan Nicholasffdc3e62019-09-19 16:58:33 -04001977 this->writeWord(baseType.columns() + 1, out);
Ethan Nicholasac285b12019-02-12 16:05:18 -05001978 } else {
1979 this->writeWord(component, out);
1980 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001981 }
1982 }
1983 return result;
1984}
1985
Greg Daniel64773e62016-11-22 09:44:03 -05001986SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1987 const Type& operandType, SpvId lhs,
1988 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04001989 SpvOp_ ifUInt, SpvOp_ ifBool, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001990 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001991 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001992 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001993 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001994 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001995 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001996 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001997 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001998 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05001999 return result; // skip RelaxedPrecision check
ethannicholasb3058bd2016-07-01 08:22:01 -07002000 } else {
2001 ABORT("invalid operandType: %s", operandType.description().c_str());
2002 }
Ethan Nicholase77739e2019-03-14 14:04:43 -04002003 if (getActualType(resultType) == operandType && !resultType.highPrecision()) {
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002004 this->writeInstruction(SpvOpDecorate, result, SpvDecorationRelaxedPrecision,
2005 fDecorationBuffer);
2006 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002007 return result;
2008}
2009
Ethan Nicholas48e24052018-03-14 13:51:39 -04002010SpvId SPIRVCodeGenerator::foldToBool(SpvId id, const Type& operandType, SpvOp op,
2011 OutputStream& out) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002012 if (operandType.kind() == Type::kVector_Kind) {
2013 SpvId result = this->nextId();
Ethan Nicholas48e24052018-03-14 13:51:39 -04002014 this->writeInstruction(op, this->getType(*fContext.fBool_Type), result, id, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002015 return result;
2016 }
2017 return id;
2018}
2019
Ethan Nicholas68990be2017-07-13 09:36:52 -04002020SpvId SPIRVCodeGenerator::writeMatrixComparison(const Type& operandType, SpvId lhs, SpvId rhs,
2021 SpvOp_ floatOperator, SpvOp_ intOperator,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002022 SpvOp_ vectorMergeOperator, SpvOp_ mergeOperator,
Ethan Nicholas68990be2017-07-13 09:36:52 -04002023 OutputStream& out) {
2024 SpvOp_ compareOp = is_float(fContext, operandType) ? floatOperator : intOperator;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002025 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
Ethan Nicholas0df21132018-07-10 09:37:51 -04002026 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2027 operandType.rows(),
2028 1));
Ethan Nicholas68990be2017-07-13 09:36:52 -04002029 SpvId bvecType = this->getType(fContext.fBool_Type->toCompound(fContext,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002030 operandType.rows(),
Ethan Nicholas68990be2017-07-13 09:36:52 -04002031 1));
2032 SpvId boolType = this->getType(*fContext.fBool_Type);
2033 SpvId result = 0;
Ethan Nicholas0df21132018-07-10 09:37:51 -04002034 for (int i = 0; i < operandType.columns(); i++) {
2035 SpvId columnL = this->nextId();
2036 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2037 SpvId columnR = this->nextId();
2038 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002039 SpvId compare = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002040 this->writeInstruction(compareOp, bvecType, compare, columnL, columnR, out);
2041 SpvId merge = this->nextId();
2042 this->writeInstruction(vectorMergeOperator, boolType, merge, compare, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002043 if (result != 0) {
2044 SpvId next = this->nextId();
Ethan Nicholas0df21132018-07-10 09:37:51 -04002045 this->writeInstruction(mergeOperator, boolType, next, result, merge, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002046 result = next;
2047 }
2048 else {
Ethan Nicholas0df21132018-07-10 09:37:51 -04002049 result = merge;
Ethan Nicholas68990be2017-07-13 09:36:52 -04002050 }
2051 }
2052 return result;
2053}
2054
Ethan Nicholas0df21132018-07-10 09:37:51 -04002055SpvId SPIRVCodeGenerator::writeComponentwiseMatrixBinary(const Type& operandType, SpvId lhs,
2056 SpvId rhs, SpvOp_ floatOperator,
2057 SpvOp_ intOperator,
2058 OutputStream& out) {
2059 SpvOp_ op = is_float(fContext, operandType) ? floatOperator : intOperator;
2060 SkASSERT(operandType.kind() == Type::kMatrix_Kind);
2061 SpvId columnType = this->getType(operandType.componentType().toCompound(fContext,
2062 operandType.rows(),
2063 1));
2064 SpvId columns[4];
2065 for (int i = 0; i < operandType.columns(); i++) {
2066 SpvId columnL = this->nextId();
2067 this->writeInstruction(SpvOpCompositeExtract, columnType, columnL, lhs, i, out);
2068 SpvId columnR = this->nextId();
2069 this->writeInstruction(SpvOpCompositeExtract, columnType, columnR, rhs, i, out);
2070 columns[i] = this->nextId();
2071 this->writeInstruction(op, columnType, columns[i], columnL, columnR, out);
2072 }
2073 SpvId result = this->nextId();
2074 this->writeOpCode(SpvOpCompositeConstruct, 3 + operandType.columns(), out);
2075 this->writeWord(this->getType(operandType), out);
2076 this->writeWord(result, out);
2077 for (int i = 0; i < operandType.columns(); i++) {
2078 this->writeWord(columns[i], out);
2079 }
2080 return result;
2081}
2082
Ethan Nicholas49465b42019-04-17 12:22:21 -04002083std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2084 if (type.isInteger()) {
2085 return std::unique_ptr<Expression>(new IntLiteral(-1, 1, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002086 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002087 else if (type.isFloat()) {
2088 return std::unique_ptr<Expression>(new FloatLiteral(-1, 1.0, &type));
ethannicholasb3058bd2016-07-01 08:22:01 -07002089 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002090 ABORT("math is unsupported on type '%s'", type.name().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07002091 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002092}
2093
2094SpvId SPIRVCodeGenerator::writeBinaryExpression(const Type& leftType, SpvId lhs, Token::Kind op,
2095 const Type& rightType, SpvId rhs,
2096 const Type& resultType, OutputStream& out) {
Ethan Nicholasffdc3e62019-09-19 16:58:33 -04002097 // it's important to handle comma early, so we don't end up vectorizing the operands
2098 if (op == Token::COMMA) {
2099 return rhs;
2100 }
2101
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002102 Type tmp("<invalid>");
Ethan Nicholas48e24052018-03-14 13:51:39 -04002103 // overall type we are operating on: float2, int, uint4...
ethannicholasb3058bd2016-07-01 08:22:01 -07002104 const Type* operandType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002105 // IR allows mismatched types in expressions (e.g. float2 * float), but they need special
2106 // handling in SPIR-V
Ethan Nicholas49465b42019-04-17 12:22:21 -04002107 if (this->getActualType(leftType) != this->getActualType(rightType)) {
2108 if (leftType.kind() == Type::kVector_Kind && rightType.isNumber()) {
2109 if (op == Token::SLASH) {
2110 SpvId one = this->writeExpression(*create_literal_1(fContext, rightType), out);
2111 SpvId inverse = this->nextId();
2112 this->writeInstruction(SpvOpFDiv, this->getType(rightType), inverse, one, rhs, out);
2113 rhs = inverse;
2114 op = Token::STAR;
2115 }
2116 if (op == Token::STAR) {
2117 SpvId result = this->nextId();
2118 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2119 result, lhs, rhs, out);
2120 return result;
2121 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002122 // promote number to vector
2123 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002124 const Type& vecType = leftType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002125 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2126 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002127 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002128 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002129 this->writeWord(rhs, out);
2130 }
2131 rhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002132 operandType = &leftType;
2133 } else if (rightType.kind() == Type::kVector_Kind && leftType.isNumber()) {
2134 if (op == Token::STAR) {
2135 SpvId result = this->nextId();
2136 this->writeInstruction(SpvOpVectorTimesScalar, this->getType(resultType),
2137 result, rhs, lhs, out);
2138 return result;
2139 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002140 // promote number to vector
2141 SpvId vec = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002142 const Type& vecType = rightType;
Ethan Nicholas48e24052018-03-14 13:51:39 -04002143 this->writeOpCode(SpvOpCompositeConstruct, 3 + vecType.columns(), out);
2144 this->writeWord(this->getType(vecType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002145 this->writeWord(vec, out);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002146 for (int i = 0; i < vecType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002147 this->writeWord(lhs, out);
2148 }
2149 lhs = vec;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002150 operandType = &rightType;
2151 } else if (leftType.kind() == Type::kMatrix_Kind) {
2152 SpvOp_ spvop;
2153 if (rightType.kind() == Type::kMatrix_Kind) {
2154 spvop = SpvOpMatrixTimesMatrix;
2155 } else if (rightType.kind() == Type::kVector_Kind) {
2156 spvop = SpvOpMatrixTimesVector;
ethannicholasb3058bd2016-07-01 08:22:01 -07002157 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002158 SkASSERT(rightType.kind() == Type::kScalar_Kind);
2159 spvop = SpvOpMatrixTimesScalar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002160 }
2161 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002162 this->writeInstruction(spvop, this->getType(resultType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002163 return result;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002164 } else if (rightType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002165 SpvId result = this->nextId();
Ethan Nicholas49465b42019-04-17 12:22:21 -04002166 if (leftType.kind() == Type::kVector_Kind) {
2167 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(resultType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002168 lhs, rhs, out);
2169 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002170 SkASSERT(leftType.kind() == Type::kScalar_Kind);
2171 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(resultType), result,
2172 rhs, lhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002173 }
2174 return result;
2175 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002176 SkASSERT(false);
2177 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002178 }
2179 } else {
Ethan Nicholas49465b42019-04-17 12:22:21 -04002180 tmp = this->getActualType(leftType);
Ethan Nicholasf7b88202017-09-18 14:10:39 -04002181 operandType = &tmp;
Ethan Nicholas49465b42019-04-17 12:22:21 -04002182 SkASSERT(*operandType == this->getActualType(rightType));
ethannicholasb3058bd2016-07-01 08:22:01 -07002183 }
Ethan Nicholas49465b42019-04-17 12:22:21 -04002184 switch (op) {
Ethan Nicholasef653b82017-02-21 13:50:00 -05002185 case Token::EQEQ: {
Ethan Nicholas68990be2017-07-13 09:36:52 -04002186 if (operandType->kind() == Type::kMatrix_Kind) {
2187 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002188 SpvOpIEqual, SpvOpAll, SpvOpLogicalAnd, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002189 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002190 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002191 const Type* tmpType;
2192 if (operandType->kind() == Type::kVector_Kind) {
2193 tmpType = &fContext.fBool_Type->toCompound(fContext,
2194 operandType->columns(),
2195 operandType->rows());
2196 } else {
2197 tmpType = &resultType;
2198 }
2199 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002200 SpvOpFOrdEqual, SpvOpIEqual,
2201 SpvOpIEqual, SpvOpLogicalEqual, out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002202 *operandType, SpvOpAll, out);
Ethan Nicholasef653b82017-02-21 13:50:00 -05002203 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002204 case Token::NEQ:
Ethan Nicholas68990be2017-07-13 09:36:52 -04002205 if (operandType->kind() == Type::kMatrix_Kind) {
2206 return this->writeMatrixComparison(*operandType, lhs, rhs, SpvOpFOrdNotEqual,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002207 SpvOpINotEqual, SpvOpAny, SpvOpLogicalOr, out);
Ethan Nicholas68990be2017-07-13 09:36:52 -04002208 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002209 SkASSERT(resultType == *fContext.fBool_Type);
Ethan Nicholas48e24052018-03-14 13:51:39 -04002210 const Type* tmpType;
2211 if (operandType->kind() == Type::kVector_Kind) {
2212 tmpType = &fContext.fBool_Type->toCompound(fContext,
2213 operandType->columns(),
2214 operandType->rows());
2215 } else {
2216 tmpType = &resultType;
2217 }
2218 return this->foldToBool(this->writeBinaryOperation(*tmpType, *operandType, lhs, rhs,
Ethan Nicholasef653b82017-02-21 13:50:00 -05002219 SpvOpFOrdNotEqual, SpvOpINotEqual,
2220 SpvOpINotEqual, SpvOpLogicalNotEqual,
2221 out),
Ethan Nicholas48e24052018-03-14 13:51:39 -04002222 *operandType, SpvOpAny, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002223 case Token::GT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002224 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002225 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2226 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002227 SpvOpUGreaterThan, SpvOpUndef, out);
2228 case Token::LT:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002229 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002230 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002231 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
2232 case Token::GTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002233 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002234 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2235 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002236 SpvOpUGreaterThanEqual, SpvOpUndef, out);
2237 case Token::LTEQ:
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002238 SkASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002239 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2240 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002241 SpvOpULessThanEqual, SpvOpUndef, out);
2242 case Token::PLUS:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002243 if (leftType.kind() == Type::kMatrix_Kind &&
2244 rightType.kind() == Type::kMatrix_Kind) {
2245 SkASSERT(leftType == rightType);
2246 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002247 SpvOpFAdd, SpvOpIAdd, out);
2248 }
Greg Daniel64773e62016-11-22 09:44:03 -05002249 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002250 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2251 case Token::MINUS:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002252 if (leftType.kind() == Type::kMatrix_Kind &&
2253 rightType.kind() == Type::kMatrix_Kind) {
2254 SkASSERT(leftType == rightType);
2255 return this->writeComponentwiseMatrixBinary(leftType, lhs, rhs,
Ethan Nicholas0df21132018-07-10 09:37:51 -04002256 SpvOpFSub, SpvOpISub, out);
2257 }
Greg Daniel64773e62016-11-22 09:44:03 -05002258 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002259 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2260 case Token::STAR:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002261 if (leftType.kind() == Type::kMatrix_Kind &&
2262 rightType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002263 // matrix multiply
2264 SpvId result = this->nextId();
2265 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2266 lhs, rhs, out);
2267 return result;
2268 }
Greg Daniel64773e62016-11-22 09:44:03 -05002269 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002270 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2271 case Token::SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002272 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002273 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
Ethan Nicholasb3d0f7c2017-05-17 13:13:21 -04002274 case Token::PERCENT:
2275 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMod,
2276 SpvOpSMod, SpvOpUMod, SpvOpUndef, out);
Ethan Nicholasfd444be2017-07-05 10:05:54 -04002277 case Token::SHL:
2278 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2279 SpvOpShiftLeftLogical, SpvOpShiftLeftLogical,
2280 SpvOpUndef, out);
2281 case Token::SHR:
2282 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2283 SpvOpShiftRightArithmetic, SpvOpShiftRightLogical,
2284 SpvOpUndef, out);
2285 case Token::BITWISEAND:
2286 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2287 SpvOpBitwiseAnd, SpvOpBitwiseAnd, SpvOpUndef, out);
2288 case Token::BITWISEOR:
2289 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2290 SpvOpBitwiseOr, SpvOpBitwiseOr, SpvOpUndef, out);
2291 case Token::BITWISEXOR:
2292 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpUndef,
2293 SpvOpBitwiseXor, SpvOpBitwiseXor, SpvOpUndef, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002294 default:
Ethan Nicholas49465b42019-04-17 12:22:21 -04002295 SkASSERT(false);
2296 return -1;
ethannicholasb3058bd2016-07-01 08:22:01 -07002297 }
2298}
2299
Ethan Nicholas49465b42019-04-17 12:22:21 -04002300SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, OutputStream& out) {
2301 // handle cases where we don't necessarily evaluate both LHS and RHS
2302 switch (b.fOperator) {
2303 case Token::EQ: {
2304 SpvId rhs = this->writeExpression(*b.fRight, out);
2305 this->getLValue(*b.fLeft, out)->store(rhs, out);
2306 return rhs;
2307 }
2308 case Token::LOGICALAND:
2309 return this->writeLogicalAnd(b, out);
2310 case Token::LOGICALOR:
2311 return this->writeLogicalOr(b, out);
2312 default:
2313 break;
2314 }
2315
2316 std::unique_ptr<LValue> lvalue;
2317 SpvId lhs;
2318 if (is_assignment(b.fOperator)) {
2319 lvalue = this->getLValue(*b.fLeft, out);
2320 lhs = lvalue->load(out);
2321 } else {
2322 lvalue = nullptr;
2323 lhs = this->writeExpression(*b.fLeft, out);
2324 }
2325 SpvId rhs = this->writeExpression(*b.fRight, out);
2326 SpvId result = this->writeBinaryExpression(b.fLeft->fType, lhs, remove_assignment(b.fOperator),
2327 b.fRight->fType, rhs, b.fType, out);
2328 if (lvalue) {
2329 lvalue->store(result, out);
2330 }
2331 return result;
2332}
2333
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002334SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002335 SkASSERT(a.fOperator == Token::LOGICALAND);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002336 BoolLiteral falseLiteral(fContext, -1, false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002337 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2338 SpvId lhs = this->writeExpression(*a.fLeft, out);
2339 SpvId rhsLabel = this->nextId();
2340 SpvId end = this->nextId();
2341 SpvId lhsBlock = fCurrentBlock;
2342 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2343 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2344 this->writeLabel(rhsLabel, out);
2345 SpvId rhs = this->writeExpression(*a.fRight, out);
2346 SpvId rhsBlock = fCurrentBlock;
2347 this->writeInstruction(SpvOpBranch, end, out);
2348 this->writeLabel(end, out);
2349 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002350 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002351 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002352 return result;
2353}
2354
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002355SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002356 SkASSERT(o.fOperator == Token::LOGICALOR);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002357 BoolLiteral trueLiteral(fContext, -1, true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002358 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2359 SpvId lhs = this->writeExpression(*o.fLeft, out);
2360 SpvId rhsLabel = this->nextId();
2361 SpvId end = this->nextId();
2362 SpvId lhsBlock = fCurrentBlock;
2363 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2364 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2365 this->writeLabel(rhsLabel, out);
2366 SpvId rhs = this->writeExpression(*o.fRight, out);
2367 SpvId rhsBlock = fCurrentBlock;
2368 this->writeInstruction(SpvOpBranch, end, out);
2369 this->writeLabel(end, out);
2370 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002371 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002372 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002373 return result;
2374}
2375
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002376SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002377 SpvId test = this->writeExpression(*t.fTest, out);
Ethan Nicholas0f21c232018-07-23 09:25:40 -04002378 if (t.fIfTrue->fType.columns() == 1 && t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002379 // both true and false are constants, can just use OpSelect
2380 SpvId result = this->nextId();
2381 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2382 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
Greg Daniel64773e62016-11-22 09:44:03 -05002383 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002384 out);
2385 return result;
2386 }
Greg Daniel64773e62016-11-22 09:44:03 -05002387 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002388 // Adreno. Switched to storing the result in a temp variable as glslang does.
2389 SpvId var = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002390 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002391 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002392 SpvId trueLabel = this->nextId();
2393 SpvId falseLabel = this->nextId();
2394 SpvId end = this->nextId();
2395 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2396 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2397 this->writeLabel(trueLabel, out);
2398 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2399 this->writeInstruction(SpvOpBranch, end, out);
2400 this->writeLabel(falseLabel, out);
2401 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2402 this->writeInstruction(SpvOpBranch, end, out);
2403 this->writeLabel(end, out);
2404 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002405 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002406 this->writePrecisionModifier(t.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002407 return result;
2408}
2409
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002410SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002411 if (p.fOperator == Token::MINUS) {
2412 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002413 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002414 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002415 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002416 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002417 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002418 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2419 } else {
2420 ABORT("unsupported prefix expression %s", p.description().c_str());
Brian Salomon23356442018-11-30 15:33:19 -05002421 }
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002422 this->writePrecisionModifier(p.fType, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07002423 return result;
2424 }
2425 switch (p.fOperator) {
2426 case Token::PLUS:
2427 return this->writeExpression(*p.fOperand, out);
2428 case Token::PLUSPLUS: {
2429 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002430 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002431 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2432 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002433 out);
2434 lv->store(result, out);
2435 return result;
2436 }
2437 case Token::MINUSMINUS: {
2438 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002439 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002440 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2441 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002442 out);
2443 lv->store(result, out);
2444 return result;
2445 }
ethannicholas5961bc92016-10-12 06:39:56 -07002446 case Token::LOGICALNOT: {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002447 SkASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002448 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002449 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002450 this->writeExpression(*p.fOperand, out), out);
2451 return result;
2452 }
ethannicholas5961bc92016-10-12 06:39:56 -07002453 case Token::BITWISENOT: {
2454 SpvId result = this->nextId();
2455 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2456 this->writeExpression(*p.fOperand, out), out);
2457 return result;
2458 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002459 default:
2460 ABORT("unsupported prefix expression: %s", p.description().c_str());
2461 }
2462}
2463
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002464SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002465 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2466 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002467 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002468 switch (p.fOperator) {
2469 case Token::PLUSPLUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002470 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002471 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2472 lv->store(temp, out);
2473 return result;
2474 }
2475 case Token::MINUSMINUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002476 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002477 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2478 lv->store(temp, out);
2479 return result;
2480 }
2481 default:
2482 ABORT("unsupported postfix expression %s", p.description().c_str());
2483 }
2484}
2485
ethannicholasf789b382016-08-03 12:43:36 -07002486SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002487 if (b.fValue) {
2488 if (fBoolTrue == 0) {
2489 fBoolTrue = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002490 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002491 fConstantBuffer);
2492 }
2493 return fBoolTrue;
2494 } else {
2495 if (fBoolFalse == 0) {
2496 fBoolFalse = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002497 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002498 fConstantBuffer);
2499 }
2500 return fBoolFalse;
2501 }
2502}
2503
ethannicholasf789b382016-08-03 12:43:36 -07002504SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002505 ConstantType type;
ethannicholasd598f792016-07-25 10:08:54 -07002506 if (i.fType == *fContext.fInt_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002507 type = ConstantType::kInt;
2508 } else if (i.fType == *fContext.fUInt_Type) {
2509 type = ConstantType::kUInt;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002510 } else if (i.fType == *fContext.fShort_Type || i.fType == *fContext.fByte_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002511 type = ConstantType::kShort;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002512 } else if (i.fType == *fContext.fUShort_Type || i.fType == *fContext.fUByte_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002513 type = ConstantType::kUShort;
Ethan Nicholasc2d84bf2019-09-09 10:49:15 -04002514 } else {
2515 SkASSERT(false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002516 }
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002517 std::pair<ConstantValue, ConstantType> key(i.fValue, type);
2518 auto entry = fNumberConstants.find(key);
2519 if (entry == fNumberConstants.end()) {
2520 SpvId result = this->nextId();
2521 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
2522 fConstantBuffer);
2523 fNumberConstants[key] = result;
2524 return result;
2525 }
2526 return entry->second;
ethannicholasb3058bd2016-07-01 08:22:01 -07002527}
2528
ethannicholasf789b382016-08-03 12:43:36 -07002529SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
Ethan Nicholase1f55022019-02-05 17:17:40 -05002530 if (f.fType != *fContext.fDouble_Type) {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002531 ConstantType type;
2532 if (f.fType == *fContext.fHalf_Type) {
2533 type = ConstantType::kHalf;
2534 } else {
2535 type = ConstantType::kFloat;
2536 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002537 float value = (float) f.fValue;
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002538 std::pair<ConstantValue, ConstantType> key(f.fValue, type);
2539 auto entry = fNumberConstants.find(key);
2540 if (entry == fNumberConstants.end()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002541 SpvId result = this->nextId();
2542 uint32_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002543 SkASSERT(sizeof(bits) == sizeof(value));
ethannicholasb3058bd2016-07-01 08:22:01 -07002544 memcpy(&bits, &value, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002545 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
ethannicholasb3058bd2016-07-01 08:22:01 -07002546 fConstantBuffer);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002547 fNumberConstants[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002548 return result;
2549 }
2550 return entry->second;
2551 } else {
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002552 std::pair<ConstantValue, ConstantType> key(f.fValue, ConstantType::kDouble);
2553 auto entry = fNumberConstants.find(key);
2554 if (entry == fNumberConstants.end()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002555 SpvId result = this->nextId();
2556 uint64_t bits;
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002557 SkASSERT(sizeof(bits) == sizeof(f.fValue));
ethannicholasb3058bd2016-07-01 08:22:01 -07002558 memcpy(&bits, &f.fValue, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002559 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002560 bits & 0xffffffff, bits >> 32, fConstantBuffer);
Ethan Nicholascc5d3e02019-04-19 09:50:56 -04002561 fNumberConstants[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002562 return result;
2563 }
2564 return entry->second;
2565 }
2566}
2567
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002568SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002569 SpvId result = fFunctionMap[&f];
Greg Daniel64773e62016-11-22 09:44:03 -05002570 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002571 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002572 this->writeInstruction(SpvOpName, result, f.fName, fNameBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002573 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002574 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002575 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002576 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002577 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002578 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2579 }
2580 return result;
2581}
2582
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002583SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, OutputStream& out) {
2584 fVariableBuffer.reset();
ethannicholasb3058bd2016-07-01 08:22:01 -07002585 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2586 this->writeLabel(this->nextId(), out);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002587 StringStream bodyBuffer;
Ethan Nicholascb670962017-04-20 19:31:52 -04002588 this->writeBlock((Block&) *f.fBody, bodyBuffer);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002589 write_stringstream(fVariableBuffer, out);
Ethan Nicholas8eb64d32018-12-21 14:50:42 -05002590 if (f.fDeclaration.fName == "main") {
2591 write_stringstream(fGlobalInitializersBuffer, out);
2592 }
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002593 write_stringstream(bodyBuffer, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002594 if (fCurrentBlock) {
Ethan Nicholas70a44b22017-11-30 09:09:16 -05002595 if (f.fDeclaration.fReturnType == *fContext.fVoid_Type) {
2596 this->writeInstruction(SpvOpReturn, out);
2597 } else {
2598 this->writeInstruction(SpvOpUnreachable, out);
2599 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002600 }
2601 this->writeInstruction(SpvOpFunctionEnd, out);
2602 return result;
2603}
2604
2605void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2606 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002607 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002608 fDecorationBuffer);
2609 }
2610 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002611 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002612 fDecorationBuffer);
2613 }
2614 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002615 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002616 fDecorationBuffer);
2617 }
2618 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002619 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002620 fDecorationBuffer);
2621 }
Greg Daniel64773e62016-11-22 09:44:03 -05002622 if (layout.fInputAttachmentIndex >= 0) {
2623 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2624 layout.fInputAttachmentIndex, fDecorationBuffer);
Ethan Nicholasbe1099f2018-01-11 16:09:05 -05002625 fCapabilities |= (((uint64_t) 1) << SpvCapabilityInputAttachment);
Greg Daniel64773e62016-11-22 09:44:03 -05002626 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04002627 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN &&
Greg Daniele6ab9982018-08-22 13:56:32 +00002628 layout.fBuiltin != SK_IN_BUILTIN && layout.fBuiltin != SK_OUT_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002629 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002630 fDecorationBuffer);
2631 }
2632}
2633
2634void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2635 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002636 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002637 layout.fLocation, fDecorationBuffer);
2638 }
2639 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002640 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002641 layout.fBinding, fDecorationBuffer);
2642 }
2643 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002644 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002645 layout.fIndex, fDecorationBuffer);
2646 }
2647 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002648 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002649 layout.fSet, fDecorationBuffer);
2650 }
Greg Daniel64773e62016-11-22 09:44:03 -05002651 if (layout.fInputAttachmentIndex >= 0) {
2652 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2653 layout.fInputAttachmentIndex, fDecorationBuffer);
2654 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002655 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002656 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002657 layout.fBuiltin, fDecorationBuffer);
2658 }
2659}
2660
Ethan Nicholas81d15112018-07-13 12:48:50 -04002661static void update_sk_in_count(const Modifiers& m, int* outSkInCount) {
2662 switch (m.fLayout.fPrimitive) {
2663 case Layout::kPoints_Primitive:
2664 *outSkInCount = 1;
2665 break;
2666 case Layout::kLines_Primitive:
2667 *outSkInCount = 2;
2668 break;
2669 case Layout::kLinesAdjacency_Primitive:
2670 *outSkInCount = 4;
2671 break;
2672 case Layout::kTriangles_Primitive:
2673 *outSkInCount = 3;
2674 break;
2675 case Layout::kTrianglesAdjacency_Primitive:
2676 *outSkInCount = 6;
2677 break;
2678 default:
2679 return;
2680 }
2681}
2682
ethannicholasf789b382016-08-03 12:43:36 -07002683SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
Ethan Nicholas361941e2017-05-30 15:41:07 -04002684 bool isBuffer = (0 != (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag));
Ethan Nicholas39204fd2017-11-27 13:12:30 -05002685 bool pushConstant = (0 != (intf.fVariable.fModifiers.fLayout.fFlags &
2686 Layout::kPushConstant_Flag));
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002687 MemoryLayout memoryLayout = (pushConstant || isBuffer) ?
2688 MemoryLayout(MemoryLayout::k430_Standard) :
2689 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002690 SpvId result = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002691 const Type* type = &intf.fVariable.fType;
Greg Daniele6ab9982018-08-22 13:56:32 +00002692 if (fProgram.fInputs.fRTHeight) {
2693 SkASSERT(fRTHeightStructId == (SpvId) -1);
2694 SkASSERT(fRTHeightFieldIndex == (SpvId) -1);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002695 std::vector<Type::Field> fields = type->fields();
Greg Daniele6ab9982018-08-22 13:56:32 +00002696 fRTHeightStructId = result;
2697 fRTHeightFieldIndex = fields.size();
2698 fields.emplace_back(Modifiers(), StringFragment(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002699 type = new Type(type->fOffset, type->name(), fields);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002700 }
Ethan Nicholas5226b772018-05-03 16:20:41 -04002701 SpvId typeId;
2702 if (intf.fVariable.fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2703 for (const auto& e : fProgram) {
2704 if (e.fKind == ProgramElement::kModifiers_Kind) {
2705 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholas81d15112018-07-13 12:48:50 -04002706 update_sk_in_count(m, &fSkInCount);
Ethan Nicholas5226b772018-05-03 16:20:41 -04002707 }
2708 }
2709 typeId = this->getType(Type("sk_in", Type::kArray_Kind, intf.fVariable.fType.componentType(),
2710 fSkInCount), memoryLayout);
2711 } else {
2712 typeId = this->getType(*type, memoryLayout);
2713 }
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002714 if (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag) {
2715 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBufferBlock, fDecorationBuffer);
Ethan Nicholas6ac8d362019-01-22 21:43:55 +00002716 } else if (intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
2717 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002718 }
ethannicholasd598f792016-07-25 10:08:54 -07002719 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002720 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002721 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002722 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
Ethan Nicholas8d2ba442018-03-16 16:40:36 -04002723 Layout layout = intf.fVariable.fModifiers.fLayout;
2724 if (intf.fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag && layout.fSet == -1) {
2725 layout.fSet = 0;
2726 }
2727 this->writeLayout(layout, result);
ethannicholasd598f792016-07-25 10:08:54 -07002728 fVariableMap[&intf.fVariable] = result;
Greg Daniele6ab9982018-08-22 13:56:32 +00002729 if (fProgram.fInputs.fRTHeight) {
Ethan Nicholas39b101b2017-03-01 12:07:28 -05002730 delete type;
2731 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002732 return result;
2733}
2734
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002735void SPIRVCodeGenerator::writePrecisionModifier(const Type& type, SpvId id) {
Ethan Nicholas10e93b62019-03-20 10:46:14 -04002736 this->writePrecisionModifier(type.highPrecision() ? Precision::kHigh : Precision::kLow, id);
2737}
2738
2739void SPIRVCodeGenerator::writePrecisionModifier(Precision precision, SpvId id) {
2740 if (precision == Precision::kLow) {
Ethan Nicholasa51d7132017-06-09 10:47:31 -04002741 this->writeInstruction(SpvOpDecorate, id, SpvDecorationRelaxedPrecision, fDecorationBuffer);
2742 }
2743}
2744
ethannicholas5961bc92016-10-12 06:39:56 -07002745#define BUILTIN_IGNORE 9999
Greg Daniel64773e62016-11-22 09:44:03 -05002746void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002747 OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002748 for (size_t i = 0; i < decl.fVars.size(); i++) {
2749 if (decl.fVars[i]->fKind == Statement::kNop_Kind) {
2750 continue;
2751 }
2752 const VarDeclaration& varDecl = (VarDeclaration&) *decl.fVars[i];
2753 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002754 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2755 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002756 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002757 Modifiers::kWriteOnly_Flag |
2758 Modifiers::kCoherent_Flag |
2759 Modifiers::kVolatile_Flag |
2760 Modifiers::kRestrict_Flag)));
ethannicholas5961bc92016-10-12 06:39:56 -07002761 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2762 continue;
2763 }
2764 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2765 kind != Program::kFragment_Kind) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002766 SkASSERT(!fProgram.fSettings.fFragColorIsInOut);
ethannicholas5961bc92016-10-12 06:39:56 -07002767 continue;
2768 }
Ethan Nicholas86a43402017-01-19 13:32:00 -05002769 if (!var->fReadCount && !var->fWriteCount &&
ethannicholas14fe8cc2016-09-07 13:37:16 -07002770 !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
2771 Modifiers::kOut_Flag |
Ethan Nicholas0dd30d92017-05-01 16:57:07 -04002772 Modifiers::kUniform_Flag |
2773 Modifiers::kBuffer_Flag))) {
ethannicholasd598f792016-07-25 10:08:54 -07002774 // variable is dead and not an input / output var (the Vulkan debug layers complain if
2775 // we elide an interface var, even if it's dead)
ethannicholasb3058bd2016-07-01 08:22:01 -07002776 continue;
2777 }
2778 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002779 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002780 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002781 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002782 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002783 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
Stephen Whiteff5d7a22019-07-26 17:42:06 -04002784 if (var->fType.kind() == Type::kSampler_Kind ||
2785 var->fType.kind() == Type::kSeparateSampler_Kind ||
2786 var->fType.kind() == Type::kTexture_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002787 storageClass = SpvStorageClassUniformConstant;
2788 } else {
2789 storageClass = SpvStorageClassUniform;
2790 }
2791 } else {
2792 storageClass = SpvStorageClassPrivate;
2793 }
2794 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002795 fVariableMap[var] = id;
Ethan Nicholas5226b772018-05-03 16:20:41 -04002796 SpvId type;
2797 if (var->fModifiers.fLayout.fBuiltin == SK_IN_BUILTIN) {
2798 type = this->getPointerType(Type("sk_in", Type::kArray_Kind,
2799 var->fType.componentType(), fSkInCount),
2800 storageClass);
2801 } else {
2802 type = this->getPointerType(var->fType, storageClass);
2803 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002804 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002805 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas858fecc2019-03-07 13:19:18 -05002806 this->writePrecisionModifier(var->fType, id);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002807 if (varDecl.fValue) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002808 SkASSERT(!fCurrentBlock);
ethannicholasf789b382016-08-03 12:43:36 -07002809 fCurrentBlock = -1;
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002810 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002811 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002812 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002813 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002814 this->writeLayout(var->fModifiers.fLayout, id);
Ethan Nicholas45b0f152017-07-24 14:36:40 -04002815 if (var->fModifiers.fFlags & Modifiers::kFlat_Flag) {
2816 this->writeInstruction(SpvOpDecorate, id, SpvDecorationFlat, fDecorationBuffer);
2817 }
2818 if (var->fModifiers.fFlags & Modifiers::kNoPerspective_Flag) {
2819 this->writeInstruction(SpvOpDecorate, id, SpvDecorationNoPerspective,
2820 fDecorationBuffer);
2821 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002822 }
2823}
2824
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002825void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, OutputStream& out) {
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002826 for (const auto& stmt : decl.fVars) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002827 SkASSERT(stmt->fKind == Statement::kVarDeclaration_Kind);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002828 VarDeclaration& varDecl = (VarDeclaration&) *stmt;
2829 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002830 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2831 // in the OpenGL backend.
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04002832 SkASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
Brian Salomonf9f45122016-11-29 11:59:17 -05002833 Modifiers::kWriteOnly_Flag |
2834 Modifiers::kCoherent_Flag |
2835 Modifiers::kVolatile_Flag |
2836 Modifiers::kRestrict_Flag)));
ethannicholasb3058bd2016-07-01 08:22:01 -07002837 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002838 fVariableMap[var] = id;
2839 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002840 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002841 this->writeInstruction(SpvOpName, id, var->fName, fNameBuffer);
Ethan Nicholas82a62d22017-11-07 14:42:10 +00002842 if (varDecl.fValue) {
2843 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002844 this->writeInstruction(SpvOpStore, id, value, out);
2845 }
2846 }
2847}
2848
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002849void SPIRVCodeGenerator::writeStatement(const Statement& s, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002850 switch (s.fKind) {
Ethan Nicholascb670962017-04-20 19:31:52 -04002851 case Statement::kNop_Kind:
2852 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002853 case Statement::kBlock_Kind:
2854 this->writeBlock((Block&) s, out);
2855 break;
2856 case Statement::kExpression_Kind:
2857 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2858 break;
Greg Daniel64773e62016-11-22 09:44:03 -05002859 case Statement::kReturn_Kind:
ethannicholasb3058bd2016-07-01 08:22:01 -07002860 this->writeReturnStatement((ReturnStatement&) s, out);
2861 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002862 case Statement::kVarDeclarations_Kind:
2863 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002864 break;
2865 case Statement::kIf_Kind:
2866 this->writeIfStatement((IfStatement&) s, out);
2867 break;
2868 case Statement::kFor_Kind:
2869 this->writeForStatement((ForStatement&) s, out);
2870 break;
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002871 case Statement::kWhile_Kind:
2872 this->writeWhileStatement((WhileStatement&) s, out);
2873 break;
2874 case Statement::kDo_Kind:
2875 this->writeDoStatement((DoStatement&) s, out);
2876 break;
Ethan Nicholase92b1b12017-11-13 16:13:21 -05002877 case Statement::kSwitch_Kind:
2878 this->writeSwitchStatement((SwitchStatement&) s, out);
2879 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002880 case Statement::kBreak_Kind:
2881 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2882 break;
2883 case Statement::kContinue_Kind:
2884 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2885 break;
2886 case Statement::kDiscard_Kind:
2887 this->writeInstruction(SpvOpKill, out);
2888 break;
2889 default:
2890 ABORT("unsupported statement: %s", s.description().c_str());
2891 }
2892}
2893
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002894void SPIRVCodeGenerator::writeBlock(const Block& b, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002895 for (size_t i = 0; i < b.fStatements.size(); i++) {
2896 this->writeStatement(*b.fStatements[i], out);
2897 }
2898}
2899
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002900void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002901 SpvId test = this->writeExpression(*stmt.fTest, out);
2902 SpvId ifTrue = this->nextId();
2903 SpvId ifFalse = this->nextId();
2904 if (stmt.fIfFalse) {
2905 SpvId end = this->nextId();
2906 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2907 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2908 this->writeLabel(ifTrue, out);
2909 this->writeStatement(*stmt.fIfTrue, out);
2910 if (fCurrentBlock) {
2911 this->writeInstruction(SpvOpBranch, end, out);
2912 }
2913 this->writeLabel(ifFalse, out);
2914 this->writeStatement(*stmt.fIfFalse, out);
2915 if (fCurrentBlock) {
2916 this->writeInstruction(SpvOpBranch, end, out);
2917 }
2918 this->writeLabel(end, out);
2919 } else {
2920 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2921 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2922 this->writeLabel(ifTrue, out);
2923 this->writeStatement(*stmt.fIfTrue, out);
2924 if (fCurrentBlock) {
2925 this->writeInstruction(SpvOpBranch, ifFalse, out);
2926 }
2927 this->writeLabel(ifFalse, out);
2928 }
2929}
2930
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002931void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002932 if (f.fInitializer) {
2933 this->writeStatement(*f.fInitializer, out);
2934 }
2935 SpvId header = this->nextId();
2936 SpvId start = this->nextId();
2937 SpvId body = this->nextId();
2938 SpvId next = this->nextId();
2939 fContinueTarget.push(next);
2940 SpvId end = this->nextId();
2941 fBreakTarget.push(end);
2942 this->writeInstruction(SpvOpBranch, header, out);
2943 this->writeLabel(header, out);
2944 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002945 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002946 this->writeLabel(start, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002947 if (f.fTest) {
2948 SpvId test = this->writeExpression(*f.fTest, out);
2949 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2950 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002951 this->writeLabel(body, out);
2952 this->writeStatement(*f.fStatement, out);
2953 if (fCurrentBlock) {
2954 this->writeInstruction(SpvOpBranch, next, out);
2955 }
2956 this->writeLabel(next, out);
2957 if (f.fNext) {
2958 this->writeExpression(*f.fNext, out);
2959 }
2960 this->writeInstruction(SpvOpBranch, header, out);
2961 this->writeLabel(end, out);
2962 fBreakTarget.pop();
2963 fContinueTarget.pop();
2964}
2965
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002966void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002967 SpvId header = this->nextId();
2968 SpvId start = this->nextId();
2969 SpvId body = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04002970 SpvId continueTarget = this->nextId();
2971 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002972 SpvId end = this->nextId();
2973 fBreakTarget.push(end);
2974 this->writeInstruction(SpvOpBranch, header, out);
2975 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04002976 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002977 this->writeInstruction(SpvOpBranch, start, out);
2978 this->writeLabel(start, out);
2979 SpvId test = this->writeExpression(*w.fTest, out);
2980 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2981 this->writeLabel(body, out);
2982 this->writeStatement(*w.fStatement, out);
2983 if (fCurrentBlock) {
Ethan Nicholas0d997662019-04-08 09:46:01 -04002984 this->writeInstruction(SpvOpBranch, continueTarget, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002985 }
Ethan Nicholas0d997662019-04-08 09:46:01 -04002986 this->writeLabel(continueTarget, out);
2987 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002988 this->writeLabel(end, out);
2989 fBreakTarget.pop();
2990 fContinueTarget.pop();
2991}
2992
Ethan Nicholas0df1b042017-03-31 13:56:23 -04002993void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) {
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002994 // We believe the do loop code below will work, but Skia doesn't actually use them and
2995 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2996 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2997 // message, simply remove the error call below to see whether our do loop support actually
2998 // works.
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07002999 fErrors.error(d.fOffset, "internal error: do loop support has been disabled in SPIR-V, see "
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003000 "SkSLSPIRVCodeGenerator.cpp for details");
3001
3002 SpvId header = this->nextId();
3003 SpvId start = this->nextId();
3004 SpvId next = this->nextId();
Ethan Nicholas0d997662019-04-08 09:46:01 -04003005 SpvId continueTarget = this->nextId();
3006 fContinueTarget.push(continueTarget);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003007 SpvId end = this->nextId();
3008 fBreakTarget.push(end);
3009 this->writeInstruction(SpvOpBranch, header, out);
3010 this->writeLabel(header, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003011 this->writeInstruction(SpvOpLoopMerge, end, continueTarget, SpvLoopControlMaskNone, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003012 this->writeInstruction(SpvOpBranch, start, out);
3013 this->writeLabel(start, out);
3014 this->writeStatement(*d.fStatement, out);
3015 if (fCurrentBlock) {
3016 this->writeInstruction(SpvOpBranch, next, out);
3017 }
3018 this->writeLabel(next, out);
3019 SpvId test = this->writeExpression(*d.fTest, out);
Ethan Nicholas0d997662019-04-08 09:46:01 -04003020 this->writeInstruction(SpvOpBranchConditional, test, continueTarget, end, out);
3021 this->writeLabel(continueTarget, out);
3022 this->writeInstruction(SpvOpBranch, header, out);
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05003023 this->writeLabel(end, out);
3024 fBreakTarget.pop();
3025 fContinueTarget.pop();
3026}
3027
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003028void SPIRVCodeGenerator::writeSwitchStatement(const SwitchStatement& s, OutputStream& out) {
3029 SpvId value = this->writeExpression(*s.fValue, out);
3030 std::vector<SpvId> labels;
3031 SpvId end = this->nextId();
3032 SpvId defaultLabel = end;
3033 fBreakTarget.push(end);
3034 int size = 3;
3035 for (const auto& c : s.fCases) {
3036 SpvId label = this->nextId();
3037 labels.push_back(label);
3038 if (c->fValue) {
3039 size += 2;
3040 } else {
3041 defaultLabel = label;
3042 }
3043 }
3044 labels.push_back(end);
3045 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
3046 this->writeOpCode(SpvOpSwitch, size, out);
3047 this->writeWord(value, out);
3048 this->writeWord(defaultLabel, out);
3049 for (size_t i = 0; i < s.fCases.size(); ++i) {
3050 if (!s.fCases[i]->fValue) {
3051 continue;
3052 }
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003053 SkASSERT(s.fCases[i]->fValue->fKind == Expression::kIntLiteral_Kind);
Ethan Nicholase92b1b12017-11-13 16:13:21 -05003054 this->writeWord(((IntLiteral&) *s.fCases[i]->fValue).fValue, out);
3055 this->writeWord(labels[i], out);
3056 }
3057 for (size_t i = 0; i < s.fCases.size(); ++i) {
3058 this->writeLabel(labels[i], out);
3059 for (const auto& stmt : s.fCases[i]->fStatements) {
3060 this->writeStatement(*stmt, out);
3061 }
3062 if (fCurrentBlock) {
3063 this->writeInstruction(SpvOpBranch, labels[i + 1], out);
3064 }
3065 }
3066 this->writeLabel(end, out);
3067 fBreakTarget.pop();
3068}
3069
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003070void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003071 if (r.fExpression) {
Greg Daniel64773e62016-11-22 09:44:03 -05003072 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
ethannicholasb3058bd2016-07-01 08:22:01 -07003073 out);
3074 } else {
3075 this->writeInstruction(SpvOpReturn, out);
3076 }
3077}
3078
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003079void SPIRVCodeGenerator::writeGeometryShaderExecutionMode(SpvId entryPoint, OutputStream& out) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003080 SkASSERT(fProgram.fKind == Program::kGeometry_Kind);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003081 int invocations = 1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003082 for (const auto& e : fProgram) {
3083 if (e.fKind == ProgramElement::kModifiers_Kind) {
3084 const Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003085 if (m.fFlags & Modifiers::kIn_Flag) {
3086 if (m.fLayout.fInvocations != -1) {
3087 invocations = m.fLayout.fInvocations;
3088 }
3089 SpvId input;
3090 switch (m.fLayout.fPrimitive) {
3091 case Layout::kPoints_Primitive:
3092 input = SpvExecutionModeInputPoints;
3093 break;
3094 case Layout::kLines_Primitive:
3095 input = SpvExecutionModeInputLines;
3096 break;
3097 case Layout::kLinesAdjacency_Primitive:
3098 input = SpvExecutionModeInputLinesAdjacency;
3099 break;
3100 case Layout::kTriangles_Primitive:
3101 input = SpvExecutionModeTriangles;
3102 break;
3103 case Layout::kTrianglesAdjacency_Primitive:
3104 input = SpvExecutionModeInputTrianglesAdjacency;
3105 break;
3106 default:
3107 input = 0;
3108 break;
3109 }
Ethan Nicholas81d15112018-07-13 12:48:50 -04003110 update_sk_in_count(m, &fSkInCount);
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003111 if (input) {
3112 this->writeInstruction(SpvOpExecutionMode, entryPoint, input, out);
3113 }
3114 } else if (m.fFlags & Modifiers::kOut_Flag) {
3115 SpvId output;
3116 switch (m.fLayout.fPrimitive) {
3117 case Layout::kPoints_Primitive:
3118 output = SpvExecutionModeOutputPoints;
3119 break;
3120 case Layout::kLineStrip_Primitive:
3121 output = SpvExecutionModeOutputLineStrip;
3122 break;
3123 case Layout::kTriangleStrip_Primitive:
3124 output = SpvExecutionModeOutputTriangleStrip;
3125 break;
3126 default:
3127 output = 0;
3128 break;
3129 }
3130 if (output) {
3131 this->writeInstruction(SpvOpExecutionMode, entryPoint, output, out);
3132 }
3133 if (m.fLayout.fMaxVertices != -1) {
3134 this->writeInstruction(SpvOpExecutionMode, entryPoint,
3135 SpvExecutionModeOutputVertices, m.fLayout.fMaxVertices,
3136 out);
3137 }
3138 }
3139 }
3140 }
3141 this->writeInstruction(SpvOpExecutionMode, entryPoint, SpvExecutionModeInvocations,
3142 invocations, out);
3143}
3144
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003145void SPIRVCodeGenerator::writeInstructions(const Program& program, OutputStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07003146 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003147 StringStream body;
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003148 std::set<SpvId> interfaceVars;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003149 // assign IDs to functions, determine sk_in size
3150 int skInSize = -1;
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003151 for (const auto& e : program) {
3152 switch (e.fKind) {
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003153 case ProgramElement::kFunction_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003154 FunctionDefinition& f = (FunctionDefinition&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003155 fFunctionMap[&f.fDeclaration] = this->nextId();
3156 break;
3157 }
3158 case ProgramElement::kModifiers_Kind: {
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003159 Modifiers& m = ((ModifiersDeclaration&) e).fModifiers;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003160 if (m.fFlags & Modifiers::kIn_Flag) {
3161 switch (m.fLayout.fPrimitive) {
3162 case Layout::kPoints_Primitive: // break
3163 case Layout::kLines_Primitive:
3164 skInSize = 1;
3165 break;
3166 case Layout::kLinesAdjacency_Primitive: // break
3167 skInSize = 2;
3168 break;
3169 case Layout::kTriangles_Primitive: // break
3170 case Layout::kTrianglesAdjacency_Primitive:
3171 skInSize = 3;
3172 break;
3173 default:
3174 break;
3175 }
3176 }
3177 break;
3178 }
3179 default:
3180 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07003181 }
3182 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003183 for (const auto& e : program) {
3184 if (e.fKind == ProgramElement::kInterfaceBlock_Kind) {
3185 InterfaceBlock& intf = (InterfaceBlock&) e;
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003186 if (SK_IN_BUILTIN == intf.fVariable.fModifiers.fLayout.fBuiltin) {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003187 SkASSERT(skInSize != -1);
Ethan Nicholasb6ba82c2018-01-17 15:21:50 -05003188 intf.fSizes.emplace_back(new IntLiteral(fContext, -1, skInSize));
3189 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003190 SpvId id = this->writeInterfaceBlock(intf);
Ethan Nicholas16c11962018-03-16 12:20:54 -04003191 if (((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
3192 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) &&
3193 intf.fVariable.fModifiers.fLayout.fBuiltin == -1) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003194 interfaceVars.insert(id);
ethannicholasb3058bd2016-07-01 08:22:01 -07003195 }
3196 }
3197 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003198 for (const auto& e : program) {
3199 if (e.fKind == ProgramElement::kVar_Kind) {
3200 this->writeGlobalVars(program.fKind, ((VarDeclarations&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003201 }
3202 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003203 for (const auto& e : program) {
3204 if (e.fKind == ProgramElement::kFunction_Kind) {
3205 this->writeFunction(((FunctionDefinition&) e), body);
ethannicholasb3058bd2016-07-01 08:22:01 -07003206 }
3207 }
ethannicholasd598f792016-07-25 10:08:54 -07003208 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07003209 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07003210 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07003211 main = entry.first;
3212 }
3213 }
Ethan Nicholas1a668d22019-04-18 10:37:40 -04003214 if (!main) {
3215 fErrors.error(0, "program does not contain a main() function");
3216 return;
3217 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003218 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07003219 const Variable* var = entry.first;
Greg Daniel64773e62016-11-22 09:44:03 -05003220 if (var->fStorage == Variable::kGlobal_Storage &&
Ethan Nicholas16c11962018-03-16 12:20:54 -04003221 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
Ethan Nicholasd23c8192018-09-26 17:01:24 -04003222 (var->fModifiers.fFlags & Modifiers::kOut_Flag))) {
Ethan Nicholas8e48c1e2017-03-02 14:33:31 -05003223 interfaceVars.insert(entry.second);
ethannicholasb3058bd2016-07-01 08:22:01 -07003224 }
3225 }
3226 this->writeCapabilities(out);
3227 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
3228 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003229 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (main->fName.fLength + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07003230 (int32_t) interfaceVars.size(), out);
3231 switch (program.fKind) {
3232 case Program::kVertex_Kind:
3233 this->writeWord(SpvExecutionModelVertex, out);
3234 break;
3235 case Program::kFragment_Kind:
3236 this->writeWord(SpvExecutionModelFragment, out);
3237 break;
Ethan Nicholas52cad152017-02-16 16:37:32 -05003238 case Program::kGeometry_Kind:
3239 this->writeWord(SpvExecutionModelGeometry, out);
3240 break;
Ethan Nicholas762466e2017-06-29 10:03:38 -04003241 default:
3242 ABORT("cannot write this kind of program to SPIR-V\n");
ethannicholasb3058bd2016-07-01 08:22:01 -07003243 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003244 SpvId entryPoint = fFunctionMap[main];
3245 this->writeWord(entryPoint, out);
Ethan Nicholas5b5f0962017-09-11 13:50:14 -07003246 this->writeString(main->fName.fChars, main->fName.fLength, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003247 for (int var : interfaceVars) {
3248 this->writeWord(var, out);
3249 }
Ethan Nicholasbb155e22017-07-24 10:05:09 -04003250 if (program.fKind == Program::kGeometry_Kind) {
3251 this->writeGeometryShaderExecutionMode(entryPoint, out);
3252 }
ethannicholasb3058bd2016-07-01 08:22:01 -07003253 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05003254 this->writeInstruction(SpvOpExecutionMode,
3255 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07003256 SpvExecutionModeOriginUpperLeft,
3257 out);
3258 }
Ethan Nicholas3c6ae622018-04-24 13:06:09 -04003259 for (const auto& e : program) {
3260 if (e.fKind == ProgramElement::kExtension_Kind) {
3261 this->writeInstruction(SpvOpSourceExtension, ((Extension&) e).fName.c_str(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003262 }
3263 }
Greg Daniel64773e62016-11-22 09:44:03 -05003264
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003265 write_stringstream(fExtraGlobalsBuffer, out);
3266 write_stringstream(fNameBuffer, out);
3267 write_stringstream(fDecorationBuffer, out);
3268 write_stringstream(fConstantBuffer, out);
3269 write_stringstream(fExternalFunctionsBuffer, out);
3270 write_stringstream(body, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07003271}
3272
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003273bool SPIRVCodeGenerator::generateCode() {
Ethan Nicholasd9d33c32018-06-12 11:05:59 -04003274 SkASSERT(!fErrors.errorCount());
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003275 this->writeWord(SpvMagicNumber, *fOut);
3276 this->writeWord(SpvVersion, *fOut);
3277 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003278 StringStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003279 this->writeInstructions(fProgram, buffer);
3280 this->writeWord(fIdCount, *fOut);
3281 this->writeWord(0, *fOut); // reserved, always zero
Ethan Nicholas0df1b042017-03-31 13:56:23 -04003282 write_stringstream(buffer, *fOut);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05003283 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07003284}
3285
3286}