blob: b5cd54abae203f591fecda3f99331c2c18ed82aa [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 */
7
8#include "SkSLSPIRVCodeGenerator.h"
9
10#include "string.h"
11
12#include "GLSL.std.450.h"
13
14#include "ir/SkSLExpressionStatement.h"
15#include "ir/SkSLExtension.h"
16#include "ir/SkSLIndexExpression.h"
17#include "ir/SkSLVariableReference.h"
ethannicholas5961bc92016-10-12 06:39:56 -070018#include "SkSLCompiler.h"
ethannicholasb3058bd2016-07-01 08:22:01 -070019
20namespace SkSL {
21
22#define SPIRV_DEBUG 0
23
24static 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)
34#define SPECIAL(x) std::make_tuple(kSpecial_IntrinsicKind, k ## x ## _SpecialIntrinsic, \
35 k ## x ## _SpecialIntrinsic, k ## x ## _SpecialIntrinsic, \
36 k ## x ## _SpecialIntrinsic)
Ethan Nicholas9e1138d2016-11-21 10:39:35 -050037 fIntrinsicMap[SkString("round")] = ALL_GLSL(Round);
38 fIntrinsicMap[SkString("roundEven")] = ALL_GLSL(RoundEven);
39 fIntrinsicMap[SkString("trunc")] = ALL_GLSL(Trunc);
40 fIntrinsicMap[SkString("abs")] = BY_TYPE_GLSL(FAbs, SAbs, SAbs);
41 fIntrinsicMap[SkString("sign")] = BY_TYPE_GLSL(FSign, SSign, SSign);
42 fIntrinsicMap[SkString("floor")] = ALL_GLSL(Floor);
43 fIntrinsicMap[SkString("ceil")] = ALL_GLSL(Ceil);
44 fIntrinsicMap[SkString("fract")] = ALL_GLSL(Fract);
45 fIntrinsicMap[SkString("radians")] = ALL_GLSL(Radians);
46 fIntrinsicMap[SkString("degrees")] = ALL_GLSL(Degrees);
47 fIntrinsicMap[SkString("sin")] = ALL_GLSL(Sin);
48 fIntrinsicMap[SkString("cos")] = ALL_GLSL(Cos);
49 fIntrinsicMap[SkString("tan")] = ALL_GLSL(Tan);
50 fIntrinsicMap[SkString("asin")] = ALL_GLSL(Asin);
51 fIntrinsicMap[SkString("acos")] = ALL_GLSL(Acos);
52 fIntrinsicMap[SkString("atan")] = SPECIAL(Atan);
53 fIntrinsicMap[SkString("sinh")] = ALL_GLSL(Sinh);
54 fIntrinsicMap[SkString("cosh")] = ALL_GLSL(Cosh);
55 fIntrinsicMap[SkString("tanh")] = ALL_GLSL(Tanh);
56 fIntrinsicMap[SkString("asinh")] = ALL_GLSL(Asinh);
57 fIntrinsicMap[SkString("acosh")] = ALL_GLSL(Acosh);
58 fIntrinsicMap[SkString("atanh")] = ALL_GLSL(Atanh);
59 fIntrinsicMap[SkString("pow")] = ALL_GLSL(Pow);
60 fIntrinsicMap[SkString("exp")] = ALL_GLSL(Exp);
61 fIntrinsicMap[SkString("log")] = ALL_GLSL(Log);
62 fIntrinsicMap[SkString("exp2")] = ALL_GLSL(Exp2);
63 fIntrinsicMap[SkString("log2")] = ALL_GLSL(Log2);
64 fIntrinsicMap[SkString("sqrt")] = ALL_GLSL(Sqrt);
65 fIntrinsicMap[SkString("inversesqrt")] = ALL_GLSL(InverseSqrt);
66 fIntrinsicMap[SkString("determinant")] = ALL_GLSL(Determinant);
67 fIntrinsicMap[SkString("matrixInverse")] = ALL_GLSL(MatrixInverse);
68 fIntrinsicMap[SkString("mod")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpFMod,
69 SpvOpSMod, SpvOpUMod, SpvOpUndef);
70 fIntrinsicMap[SkString("min")] = BY_TYPE_GLSL(FMin, SMin, UMin);
71 fIntrinsicMap[SkString("max")] = BY_TYPE_GLSL(FMax, SMax, UMax);
72 fIntrinsicMap[SkString("clamp")] = BY_TYPE_GLSL(FClamp, SClamp, UClamp);
73 fIntrinsicMap[SkString("dot")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDot,
74 SpvOpUndef, SpvOpUndef, SpvOpUndef);
75 fIntrinsicMap[SkString("mix")] = ALL_GLSL(FMix);
76 fIntrinsicMap[SkString("step")] = ALL_GLSL(Step);
77 fIntrinsicMap[SkString("smoothstep")] = ALL_GLSL(SmoothStep);
78 fIntrinsicMap[SkString("fma")] = ALL_GLSL(Fma);
79 fIntrinsicMap[SkString("frexp")] = ALL_GLSL(Frexp);
80 fIntrinsicMap[SkString("ldexp")] = ALL_GLSL(Ldexp);
ethannicholasb3058bd2016-07-01 08:22:01 -070081
Ethan Nicholas9e1138d2016-11-21 10:39:35 -050082#define PACK(type) fIntrinsicMap[SkString("pack" #type)] = ALL_GLSL(Pack ## type); \
83 fIntrinsicMap[SkString("unpack" #type)] = ALL_GLSL(Unpack ## type)
ethannicholasb3058bd2016-07-01 08:22:01 -070084 PACK(Snorm4x8);
85 PACK(Unorm4x8);
86 PACK(Snorm2x16);
87 PACK(Unorm2x16);
88 PACK(Half2x16);
89 PACK(Double2x32);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -050090 fIntrinsicMap[SkString("length")] = ALL_GLSL(Length);
91 fIntrinsicMap[SkString("distance")] = ALL_GLSL(Distance);
92 fIntrinsicMap[SkString("cross")] = ALL_GLSL(Cross);
93 fIntrinsicMap[SkString("normalize")] = ALL_GLSL(Normalize);
94 fIntrinsicMap[SkString("faceForward")] = ALL_GLSL(FaceForward);
95 fIntrinsicMap[SkString("reflect")] = ALL_GLSL(Reflect);
96 fIntrinsicMap[SkString("refract")] = ALL_GLSL(Refract);
97 fIntrinsicMap[SkString("findLSB")] = ALL_GLSL(FindILsb);
98 fIntrinsicMap[SkString("findMSB")] = BY_TYPE_GLSL(FindSMsb, FindSMsb, FindUMsb);
99 fIntrinsicMap[SkString("dFdx")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdx,
100 SpvOpUndef, SpvOpUndef, SpvOpUndef);
101 fIntrinsicMap[SkString("dFdy")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy,
102 SpvOpUndef, SpvOpUndef, SpvOpUndef);
103 fIntrinsicMap[SkString("dFdy")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpDPdy,
104 SpvOpUndef, SpvOpUndef, SpvOpUndef);
105 fIntrinsicMap[SkString("texture")] = SPECIAL(Texture);
106 fIntrinsicMap[SkString("texture2D")] = SPECIAL(Texture2D);
107 fIntrinsicMap[SkString("textureProj")] = SPECIAL(TextureProj);
ethannicholasb3058bd2016-07-01 08:22:01 -0700108
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500109 fIntrinsicMap[SkString("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
110 SpvOpUndef, SpvOpUndef, SpvOpAny);
111 fIntrinsicMap[SkString("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
112 SpvOpUndef, SpvOpUndef, SpvOpAll);
113 fIntrinsicMap[SkString("equal")] = std::make_tuple(kSPIRV_IntrinsicKind,
114 SpvOpFOrdEqual, SpvOpIEqual,
115 SpvOpIEqual, SpvOpLogicalEqual);
116 fIntrinsicMap[SkString("notEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
117 SpvOpFOrdNotEqual, SpvOpINotEqual,
118 SpvOpINotEqual,
119 SpvOpLogicalNotEqual);
120 fIntrinsicMap[SkString("lessThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
121 SpvOpSLessThan, SpvOpULessThan,
122 SpvOpFOrdLessThan, SpvOpUndef);
123 fIntrinsicMap[SkString("lessThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
124 SpvOpSLessThanEqual,
125 SpvOpULessThanEqual,
126 SpvOpFOrdLessThanEqual,
127 SpvOpUndef);
128 fIntrinsicMap[SkString("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
129 SpvOpSGreaterThan,
130 SpvOpUGreaterThan,
131 SpvOpFOrdGreaterThan,
132 SpvOpUndef);
133 fIntrinsicMap[SkString("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
134 SpvOpSGreaterThanEqual,
135 SpvOpUGreaterThanEqual,
136 SpvOpFOrdGreaterThanEqual,
137 SpvOpUndef);
ethannicholasb3058bd2016-07-01 08:22:01 -0700138
139// interpolateAt* not yet supported...
140}
141
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500142void SPIRVCodeGenerator::writeWord(int32_t word, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700143#if SPIRV_DEBUG
144 out << "(" << word << ") ";
145#else
146 out.write((const char*) &word, sizeof(word));
147#endif
148}
149
ethannicholasd598f792016-07-25 10:08:54 -0700150static bool is_float(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700151 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700152 return is_float(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700153 }
ethannicholasd598f792016-07-25 10:08:54 -0700154 return type == *context.fFloat_Type || type == *context.fDouble_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700155}
156
ethannicholasd598f792016-07-25 10:08:54 -0700157static bool is_signed(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700158 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700159 return is_signed(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700160 }
ethannicholasd598f792016-07-25 10:08:54 -0700161 return type == *context.fInt_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700162}
163
ethannicholasd598f792016-07-25 10:08:54 -0700164static bool is_unsigned(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700165 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700166 return is_unsigned(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700167 }
ethannicholasd598f792016-07-25 10:08:54 -0700168 return type == *context.fUInt_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700169}
170
ethannicholasd598f792016-07-25 10:08:54 -0700171static bool is_bool(const Context& context, const Type& type) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700172 if (type.kind() == Type::kVector_Kind) {
ethannicholasd598f792016-07-25 10:08:54 -0700173 return is_bool(context, type.componentType());
ethannicholasb3058bd2016-07-01 08:22:01 -0700174 }
ethannicholasd598f792016-07-25 10:08:54 -0700175 return type == *context.fBool_Type;
ethannicholasb3058bd2016-07-01 08:22:01 -0700176}
177
ethannicholasd598f792016-07-25 10:08:54 -0700178static bool is_out(const Variable& var) {
179 return (var.fModifiers.fFlags & Modifiers::kOut_Flag) != 0;
ethannicholasb3058bd2016-07-01 08:22:01 -0700180}
181
182#if SPIRV_DEBUG
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500183static SkString opcode_text(SpvOp_ opCode) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700184 switch (opCode) {
185 case SpvOpNop:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500186 return SkString("Nop");
ethannicholasb3058bd2016-07-01 08:22:01 -0700187 case SpvOpUndef:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500188 return SkString("Undef");
ethannicholasb3058bd2016-07-01 08:22:01 -0700189 case SpvOpSourceContinued:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500190 return SkString("SourceContinued");
ethannicholasb3058bd2016-07-01 08:22:01 -0700191 case SpvOpSource:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500192 return SkString("Source");
ethannicholasb3058bd2016-07-01 08:22:01 -0700193 case SpvOpSourceExtension:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500194 return SkString("SourceExtension");
ethannicholasb3058bd2016-07-01 08:22:01 -0700195 case SpvOpName:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500196 return SkString("Name");
ethannicholasb3058bd2016-07-01 08:22:01 -0700197 case SpvOpMemberName:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500198 return SkString("MemberName");
ethannicholasb3058bd2016-07-01 08:22:01 -0700199 case SpvOpString:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500200 return SkString("String");
ethannicholasb3058bd2016-07-01 08:22:01 -0700201 case SpvOpLine:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500202 return SkString("Line");
ethannicholasb3058bd2016-07-01 08:22:01 -0700203 case SpvOpExtension:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500204 return SkString("Extension");
ethannicholasb3058bd2016-07-01 08:22:01 -0700205 case SpvOpExtInstImport:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500206 return SkString("ExtInstImport");
ethannicholasb3058bd2016-07-01 08:22:01 -0700207 case SpvOpExtInst:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500208 return SkString("ExtInst");
ethannicholasb3058bd2016-07-01 08:22:01 -0700209 case SpvOpMemoryModel:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500210 return SkString("MemoryModel");
ethannicholasb3058bd2016-07-01 08:22:01 -0700211 case SpvOpEntryPoint:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500212 return SkString("EntryPoint");
ethannicholasb3058bd2016-07-01 08:22:01 -0700213 case SpvOpExecutionMode:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500214 return SkString("ExecutionMode");
ethannicholasb3058bd2016-07-01 08:22:01 -0700215 case SpvOpCapability:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500216 return SkString("Capability");
ethannicholasb3058bd2016-07-01 08:22:01 -0700217 case SpvOpTypeVoid:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500218 return SkString("TypeVoid");
ethannicholasb3058bd2016-07-01 08:22:01 -0700219 case SpvOpTypeBool:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500220 return SkString("TypeBool");
ethannicholasb3058bd2016-07-01 08:22:01 -0700221 case SpvOpTypeInt:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500222 return SkString("TypeInt");
ethannicholasb3058bd2016-07-01 08:22:01 -0700223 case SpvOpTypeFloat:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500224 return SkString("TypeFloat");
ethannicholasb3058bd2016-07-01 08:22:01 -0700225 case SpvOpTypeVector:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500226 return SkString("TypeVector");
ethannicholasb3058bd2016-07-01 08:22:01 -0700227 case SpvOpTypeMatrix:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500228 return SkString("TypeMatrix");
ethannicholasb3058bd2016-07-01 08:22:01 -0700229 case SpvOpTypeImage:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500230 return SkString("TypeImage");
ethannicholasb3058bd2016-07-01 08:22:01 -0700231 case SpvOpTypeSampler:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500232 return SkString("TypeSampler");
ethannicholasb3058bd2016-07-01 08:22:01 -0700233 case SpvOpTypeSampledImage:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500234 return SkString("TypeSampledImage");
ethannicholasb3058bd2016-07-01 08:22:01 -0700235 case SpvOpTypeArray:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500236 return SkString("TypeArray");
ethannicholasb3058bd2016-07-01 08:22:01 -0700237 case SpvOpTypeRuntimeArray:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500238 return SkString("TypeRuntimeArray");
ethannicholasb3058bd2016-07-01 08:22:01 -0700239 case SpvOpTypeStruct:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500240 return SkString("TypeStruct");
ethannicholasb3058bd2016-07-01 08:22:01 -0700241 case SpvOpTypeOpaque:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500242 return SkString("TypeOpaque");
ethannicholasb3058bd2016-07-01 08:22:01 -0700243 case SpvOpTypePointer:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500244 return SkString("TypePointer");
ethannicholasb3058bd2016-07-01 08:22:01 -0700245 case SpvOpTypeFunction:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500246 return SkString("TypeFunction");
ethannicholasb3058bd2016-07-01 08:22:01 -0700247 case SpvOpTypeEvent:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500248 return SkString("TypeEvent");
ethannicholasb3058bd2016-07-01 08:22:01 -0700249 case SpvOpTypeDeviceEvent:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500250 return SkString("TypeDeviceEvent");
ethannicholasb3058bd2016-07-01 08:22:01 -0700251 case SpvOpTypeReserveId:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500252 return SkString("TypeReserveId");
ethannicholasb3058bd2016-07-01 08:22:01 -0700253 case SpvOpTypeQueue:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500254 return SkString("TypeQueue");
ethannicholasb3058bd2016-07-01 08:22:01 -0700255 case SpvOpTypePipe:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500256 return SkString("TypePipe");
ethannicholasb3058bd2016-07-01 08:22:01 -0700257 case SpvOpTypeForwardPointer:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500258 return SkString("TypeForwardPointer");
ethannicholasb3058bd2016-07-01 08:22:01 -0700259 case SpvOpConstantTrue:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500260 return SkString("ConstantTrue");
ethannicholasb3058bd2016-07-01 08:22:01 -0700261 case SpvOpConstantFalse:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500262 return SkString("ConstantFalse");
ethannicholasb3058bd2016-07-01 08:22:01 -0700263 case SpvOpConstant:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500264 return SkString("Constant");
ethannicholasb3058bd2016-07-01 08:22:01 -0700265 case SpvOpConstantComposite:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500266 return SkString("ConstantComposite");
ethannicholasb3058bd2016-07-01 08:22:01 -0700267 case SpvOpConstantSampler:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500268 return SkString("ConstantSampler");
ethannicholasb3058bd2016-07-01 08:22:01 -0700269 case SpvOpConstantNull:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500270 return SkString("ConstantNull");
ethannicholasb3058bd2016-07-01 08:22:01 -0700271 case SpvOpSpecConstantTrue:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500272 return SkString("SpecConstantTrue");
ethannicholasb3058bd2016-07-01 08:22:01 -0700273 case SpvOpSpecConstantFalse:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500274 return SkString("SpecConstantFalse");
ethannicholasb3058bd2016-07-01 08:22:01 -0700275 case SpvOpSpecConstant:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500276 return SkString("SpecConstant");
ethannicholasb3058bd2016-07-01 08:22:01 -0700277 case SpvOpSpecConstantComposite:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500278 return SkString("SpecConstantComposite");
ethannicholasb3058bd2016-07-01 08:22:01 -0700279 case SpvOpSpecConstantOp:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500280 return SkString("SpecConstantOp");
ethannicholasb3058bd2016-07-01 08:22:01 -0700281 case SpvOpFunction:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500282 return SkString("Function");
ethannicholasb3058bd2016-07-01 08:22:01 -0700283 case SpvOpFunctionParameter:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500284 return SkString("FunctionParameter");
ethannicholasb3058bd2016-07-01 08:22:01 -0700285 case SpvOpFunctionEnd:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500286 return SkString("FunctionEnd");
ethannicholasb3058bd2016-07-01 08:22:01 -0700287 case SpvOpFunctionCall:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500288 return SkString("FunctionCall");
ethannicholasb3058bd2016-07-01 08:22:01 -0700289 case SpvOpVariable:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500290 return SkString("Variable");
ethannicholasb3058bd2016-07-01 08:22:01 -0700291 case SpvOpImageTexelPointer:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500292 return SkString("ImageTexelPointer");
ethannicholasb3058bd2016-07-01 08:22:01 -0700293 case SpvOpLoad:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500294 return SkString("Load");
ethannicholasb3058bd2016-07-01 08:22:01 -0700295 case SpvOpStore:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500296 return SkString("Store");
ethannicholasb3058bd2016-07-01 08:22:01 -0700297 case SpvOpCopyMemory:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500298 return SkString("CopyMemory");
ethannicholasb3058bd2016-07-01 08:22:01 -0700299 case SpvOpCopyMemorySized:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500300 return SkString("CopyMemorySized");
ethannicholasb3058bd2016-07-01 08:22:01 -0700301 case SpvOpAccessChain:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500302 return SkString("AccessChain");
ethannicholasb3058bd2016-07-01 08:22:01 -0700303 case SpvOpInBoundsAccessChain:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500304 return SkString("InBoundsAccessChain");
ethannicholasb3058bd2016-07-01 08:22:01 -0700305 case SpvOpPtrAccessChain:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500306 return SkString("PtrAccessChain");
ethannicholasb3058bd2016-07-01 08:22:01 -0700307 case SpvOpArrayLength:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500308 return SkString("ArrayLength");
ethannicholasb3058bd2016-07-01 08:22:01 -0700309 case SpvOpGenericPtrMemSemantics:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500310 return SkString("GenericPtrMemSemantics");
ethannicholasb3058bd2016-07-01 08:22:01 -0700311 case SpvOpInBoundsPtrAccessChain:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500312 return SkString("InBoundsPtrAccessChain");
ethannicholasb3058bd2016-07-01 08:22:01 -0700313 case SpvOpDecorate:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500314 return SkString("Decorate");
ethannicholasb3058bd2016-07-01 08:22:01 -0700315 case SpvOpMemberDecorate:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500316 return SkString("MemberDecorate");
ethannicholasb3058bd2016-07-01 08:22:01 -0700317 case SpvOpDecorationGroup:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500318 return SkString("DecorationGroup");
ethannicholasb3058bd2016-07-01 08:22:01 -0700319 case SpvOpGroupDecorate:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500320 return SkString("GroupDecorate");
ethannicholasb3058bd2016-07-01 08:22:01 -0700321 case SpvOpGroupMemberDecorate:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500322 return SkString("GroupMemberDecorate");
ethannicholasb3058bd2016-07-01 08:22:01 -0700323 case SpvOpVectorExtractDynamic:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500324 return SkString("VectorExtractDynamic");
ethannicholasb3058bd2016-07-01 08:22:01 -0700325 case SpvOpVectorInsertDynamic:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500326 return SkString("VectorInsertDynamic");
ethannicholasb3058bd2016-07-01 08:22:01 -0700327 case SpvOpVectorShuffle:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500328 return SkString("VectorShuffle");
ethannicholasb3058bd2016-07-01 08:22:01 -0700329 case SpvOpCompositeConstruct:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500330 return SkString("CompositeConstruct");
ethannicholasb3058bd2016-07-01 08:22:01 -0700331 case SpvOpCompositeExtract:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500332 return SkString("CompositeExtract");
ethannicholasb3058bd2016-07-01 08:22:01 -0700333 case SpvOpCompositeInsert:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500334 return SkString("CompositeInsert");
ethannicholasb3058bd2016-07-01 08:22:01 -0700335 case SpvOpCopyObject:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500336 return SkString("CopyObject");
ethannicholasb3058bd2016-07-01 08:22:01 -0700337 case SpvOpTranspose:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500338 return SkString("Transpose");
ethannicholasb3058bd2016-07-01 08:22:01 -0700339 case SpvOpSampledImage:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500340 return SkString("SampledImage");
ethannicholasb3058bd2016-07-01 08:22:01 -0700341 case SpvOpImageSampleImplicitLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500342 return SkString("ImageSampleImplicitLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700343 case SpvOpImageSampleExplicitLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500344 return SkString("ImageSampleExplicitLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700345 case SpvOpImageSampleDrefImplicitLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500346 return SkString("ImageSampleDrefImplicitLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700347 case SpvOpImageSampleDrefExplicitLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500348 return SkString("ImageSampleDrefExplicitLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700349 case SpvOpImageSampleProjImplicitLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500350 return SkString("ImageSampleProjImplicitLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700351 case SpvOpImageSampleProjExplicitLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500352 return SkString("ImageSampleProjExplicitLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700353 case SpvOpImageSampleProjDrefImplicitLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500354 return SkString("ImageSampleProjDrefImplicitLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700355 case SpvOpImageSampleProjDrefExplicitLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500356 return SkString("ImageSampleProjDrefExplicitLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700357 case SpvOpImageFetch:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500358 return SkString("ImageFetch");
ethannicholasb3058bd2016-07-01 08:22:01 -0700359 case SpvOpImageGather:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500360 return SkString("ImageGather");
ethannicholasb3058bd2016-07-01 08:22:01 -0700361 case SpvOpImageDrefGather:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500362 return SkString("ImageDrefGather");
ethannicholasb3058bd2016-07-01 08:22:01 -0700363 case SpvOpImageRead:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500364 return SkString("ImageRead");
ethannicholasb3058bd2016-07-01 08:22:01 -0700365 case SpvOpImageWrite:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500366 return SkString("ImageWrite");
ethannicholasb3058bd2016-07-01 08:22:01 -0700367 case SpvOpImage:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500368 return SkString("Image");
ethannicholasb3058bd2016-07-01 08:22:01 -0700369 case SpvOpImageQueryFormat:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500370 return SkString("ImageQueryFormat");
ethannicholasb3058bd2016-07-01 08:22:01 -0700371 case SpvOpImageQueryOrder:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500372 return SkString("ImageQueryOrder");
ethannicholasb3058bd2016-07-01 08:22:01 -0700373 case SpvOpImageQuerySizeLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500374 return SkString("ImageQuerySizeLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700375 case SpvOpImageQuerySize:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500376 return SkString("ImageQuerySize");
ethannicholasb3058bd2016-07-01 08:22:01 -0700377 case SpvOpImageQueryLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500378 return SkString("ImageQueryLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700379 case SpvOpImageQueryLevels:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500380 return SkString("ImageQueryLevels");
ethannicholasb3058bd2016-07-01 08:22:01 -0700381 case SpvOpImageQuerySamples:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500382 return SkString("ImageQuerySamples");
ethannicholasb3058bd2016-07-01 08:22:01 -0700383 case SpvOpConvertFToU:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500384 return SkString("ConvertFToU");
ethannicholasb3058bd2016-07-01 08:22:01 -0700385 case SpvOpConvertFToS:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500386 return SkString("ConvertFToS");
ethannicholasb3058bd2016-07-01 08:22:01 -0700387 case SpvOpConvertSToF:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500388 return SkString("ConvertSToF");
ethannicholasb3058bd2016-07-01 08:22:01 -0700389 case SpvOpConvertUToF:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500390 return SkString("ConvertUToF");
ethannicholasb3058bd2016-07-01 08:22:01 -0700391 case SpvOpUConvert:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500392 return SkString("UConvert");
ethannicholasb3058bd2016-07-01 08:22:01 -0700393 case SpvOpSConvert:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500394 return SkString("SConvert");
ethannicholasb3058bd2016-07-01 08:22:01 -0700395 case SpvOpFConvert:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500396 return SkString("FConvert");
ethannicholasb3058bd2016-07-01 08:22:01 -0700397 case SpvOpQuantizeToF16:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500398 return SkString("QuantizeToF16");
ethannicholasb3058bd2016-07-01 08:22:01 -0700399 case SpvOpConvertPtrToU:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500400 return SkString("ConvertPtrToU");
ethannicholasb3058bd2016-07-01 08:22:01 -0700401 case SpvOpSatConvertSToU:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500402 return SkString("SatConvertSToU");
ethannicholasb3058bd2016-07-01 08:22:01 -0700403 case SpvOpSatConvertUToS:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500404 return SkString("SatConvertUToS");
ethannicholasb3058bd2016-07-01 08:22:01 -0700405 case SpvOpConvertUToPtr:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500406 return SkString("ConvertUToPtr");
ethannicholasb3058bd2016-07-01 08:22:01 -0700407 case SpvOpPtrCastToGeneric:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500408 return SkString("PtrCastToGeneric");
ethannicholasb3058bd2016-07-01 08:22:01 -0700409 case SpvOpGenericCastToPtr:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500410 return SkString("GenericCastToPtr");
ethannicholasb3058bd2016-07-01 08:22:01 -0700411 case SpvOpGenericCastToPtrExplicit:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500412 return SkString("GenericCastToPtrExplicit");
ethannicholasb3058bd2016-07-01 08:22:01 -0700413 case SpvOpBitcast:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500414 return SkString("Bitcast");
ethannicholasb3058bd2016-07-01 08:22:01 -0700415 case SpvOpSNegate:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500416 return SkString("SNegate");
ethannicholasb3058bd2016-07-01 08:22:01 -0700417 case SpvOpFNegate:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500418 return SkString("FNegate");
ethannicholasb3058bd2016-07-01 08:22:01 -0700419 case SpvOpIAdd:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500420 return SkString("IAdd");
ethannicholasb3058bd2016-07-01 08:22:01 -0700421 case SpvOpFAdd:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500422 return SkString("FAdd");
ethannicholasb3058bd2016-07-01 08:22:01 -0700423 case SpvOpISub:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500424 return SkString("ISub");
ethannicholasb3058bd2016-07-01 08:22:01 -0700425 case SpvOpFSub:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500426 return SkString("FSub");
ethannicholasb3058bd2016-07-01 08:22:01 -0700427 case SpvOpIMul:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500428 return SkString("IMul");
ethannicholasb3058bd2016-07-01 08:22:01 -0700429 case SpvOpFMul:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500430 return SkString("FMul");
ethannicholasb3058bd2016-07-01 08:22:01 -0700431 case SpvOpUDiv:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500432 return SkString("UDiv");
ethannicholasb3058bd2016-07-01 08:22:01 -0700433 case SpvOpSDiv:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500434 return SkString("SDiv");
ethannicholasb3058bd2016-07-01 08:22:01 -0700435 case SpvOpFDiv:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500436 return SkString("FDiv");
ethannicholasb3058bd2016-07-01 08:22:01 -0700437 case SpvOpUMod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500438 return SkString("UMod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700439 case SpvOpSRem:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500440 return SkString("SRem");
ethannicholasb3058bd2016-07-01 08:22:01 -0700441 case SpvOpSMod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500442 return SkString("SMod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700443 case SpvOpFRem:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500444 return SkString("FRem");
ethannicholasb3058bd2016-07-01 08:22:01 -0700445 case SpvOpFMod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500446 return SkString("FMod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700447 case SpvOpVectorTimesScalar:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500448 return SkString("VectorTimesScalar");
ethannicholasb3058bd2016-07-01 08:22:01 -0700449 case SpvOpMatrixTimesScalar:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500450 return SkString("MatrixTimesScalar");
ethannicholasb3058bd2016-07-01 08:22:01 -0700451 case SpvOpVectorTimesMatrix:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500452 return SkString("VectorTimesMatrix");
ethannicholasb3058bd2016-07-01 08:22:01 -0700453 case SpvOpMatrixTimesVector:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500454 return SkString("MatrixTimesVector");
ethannicholasb3058bd2016-07-01 08:22:01 -0700455 case SpvOpMatrixTimesMatrix:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500456 return SkString("MatrixTimesMatrix");
ethannicholasb3058bd2016-07-01 08:22:01 -0700457 case SpvOpOuterProduct:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500458 return SkString("OuterProduct");
ethannicholasb3058bd2016-07-01 08:22:01 -0700459 case SpvOpDot:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500460 return SkString("Dot");
ethannicholasb3058bd2016-07-01 08:22:01 -0700461 case SpvOpIAddCarry:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500462 return SkString("IAddCarry");
ethannicholasb3058bd2016-07-01 08:22:01 -0700463 case SpvOpISubBorrow:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500464 return SkString("ISubBorrow");
ethannicholasb3058bd2016-07-01 08:22:01 -0700465 case SpvOpUMulExtended:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500466 return SkString("UMulExtended");
ethannicholasb3058bd2016-07-01 08:22:01 -0700467 case SpvOpSMulExtended:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500468 return SkString("SMulExtended");
ethannicholasb3058bd2016-07-01 08:22:01 -0700469 case SpvOpAny:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500470 return SkString("Any");
ethannicholasb3058bd2016-07-01 08:22:01 -0700471 case SpvOpAll:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500472 return SkString("All");
ethannicholasb3058bd2016-07-01 08:22:01 -0700473 case SpvOpIsNan:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500474 return SkString("IsNan");
ethannicholasb3058bd2016-07-01 08:22:01 -0700475 case SpvOpIsInf:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500476 return SkString("IsInf");
ethannicholasb3058bd2016-07-01 08:22:01 -0700477 case SpvOpIsFinite:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500478 return SkString("IsFinite");
ethannicholasb3058bd2016-07-01 08:22:01 -0700479 case SpvOpIsNormal:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500480 return SkString("IsNormal");
ethannicholasb3058bd2016-07-01 08:22:01 -0700481 case SpvOpSignBitSet:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500482 return SkString("SignBitSet");
ethannicholasb3058bd2016-07-01 08:22:01 -0700483 case SpvOpLessOrGreater:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500484 return SkString("LessOrGreater");
ethannicholasb3058bd2016-07-01 08:22:01 -0700485 case SpvOpOrdered:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500486 return SkString("Ordered");
ethannicholasb3058bd2016-07-01 08:22:01 -0700487 case SpvOpUnordered:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500488 return SkString("Unordered");
ethannicholasb3058bd2016-07-01 08:22:01 -0700489 case SpvOpLogicalEqual:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500490 return SkString("LogicalEqual");
ethannicholasb3058bd2016-07-01 08:22:01 -0700491 case SpvOpLogicalNotEqual:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500492 return SkString("LogicalNotEqual");
ethannicholasb3058bd2016-07-01 08:22:01 -0700493 case SpvOpLogicalOr:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500494 return SkString("LogicalOr");
ethannicholasb3058bd2016-07-01 08:22:01 -0700495 case SpvOpLogicalAnd:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500496 return SkString("LogicalAnd");
ethannicholasb3058bd2016-07-01 08:22:01 -0700497 case SpvOpLogicalNot:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500498 return SkString("LogicalNot");
ethannicholasb3058bd2016-07-01 08:22:01 -0700499 case SpvOpSelect:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500500 return SkString("Select");
ethannicholasb3058bd2016-07-01 08:22:01 -0700501 case SpvOpIEqual:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500502 return SkString("IEqual");
ethannicholasb3058bd2016-07-01 08:22:01 -0700503 case SpvOpINotEqual:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500504 return SkString("INotEqual");
ethannicholasb3058bd2016-07-01 08:22:01 -0700505 case SpvOpUGreaterThan:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500506 return SkString("UGreaterThan");
ethannicholasb3058bd2016-07-01 08:22:01 -0700507 case SpvOpSGreaterThan:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500508 return SkString("SGreaterThan");
ethannicholasb3058bd2016-07-01 08:22:01 -0700509 case SpvOpUGreaterThanEqual:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500510 return SkString("UGreaterThanEqual");
ethannicholasb3058bd2016-07-01 08:22:01 -0700511 case SpvOpSGreaterThanEqual:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500512 return SkString("SGreaterThanEqual");
ethannicholasb3058bd2016-07-01 08:22:01 -0700513 case SpvOpULessThan:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500514 return SkString("ULessThan");
ethannicholasb3058bd2016-07-01 08:22:01 -0700515 case SpvOpSLessThan:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500516 return SkString("SLessThan");
ethannicholasb3058bd2016-07-01 08:22:01 -0700517 case SpvOpULessThanEqual:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500518 return SkString("ULessThanEqual");
ethannicholasb3058bd2016-07-01 08:22:01 -0700519 case SpvOpSLessThanEqual:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500520 return SkString("SLessThanEqual");
ethannicholasb3058bd2016-07-01 08:22:01 -0700521 case SpvOpFOrdEqual:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500522 return SkString("FOrdEqual");
ethannicholasb3058bd2016-07-01 08:22:01 -0700523 case SpvOpFUnordEqual:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500524 return SkString("FUnordEqual");
ethannicholasb3058bd2016-07-01 08:22:01 -0700525 case SpvOpFOrdNotEqual:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500526 return SkString("FOrdNotEqual");
ethannicholasb3058bd2016-07-01 08:22:01 -0700527 case SpvOpFUnordNotEqual:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500528 return SkString("FUnordNotEqual");
ethannicholasb3058bd2016-07-01 08:22:01 -0700529 case SpvOpFOrdLessThan:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500530 return SkString("FOrdLessThan");
ethannicholasb3058bd2016-07-01 08:22:01 -0700531 case SpvOpFUnordLessThan:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500532 return SkString("FUnordLessThan");
ethannicholasb3058bd2016-07-01 08:22:01 -0700533 case SpvOpFOrdGreaterThan:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500534 return SkString("FOrdGreaterThan");
ethannicholasb3058bd2016-07-01 08:22:01 -0700535 case SpvOpFUnordGreaterThan:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500536 return SkString("FUnordGreaterThan");
ethannicholasb3058bd2016-07-01 08:22:01 -0700537 case SpvOpFOrdLessThanEqual:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500538 return SkString("FOrdLessThanEqual");
ethannicholasb3058bd2016-07-01 08:22:01 -0700539 case SpvOpFUnordLessThanEqual:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500540 return SkString("FUnordLessThanEqual");
ethannicholasb3058bd2016-07-01 08:22:01 -0700541 case SpvOpFOrdGreaterThanEqual:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500542 return SkString("FOrdGreaterThanEqual");
ethannicholasb3058bd2016-07-01 08:22:01 -0700543 case SpvOpFUnordGreaterThanEqual:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500544 return SkString("FUnordGreaterThanEqual");
ethannicholasb3058bd2016-07-01 08:22:01 -0700545 case SpvOpShiftRightLogical:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500546 return SkString("ShiftRightLogical");
ethannicholasb3058bd2016-07-01 08:22:01 -0700547 case SpvOpShiftRightArithmetic:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500548 return SkString("ShiftRightArithmetic");
ethannicholasb3058bd2016-07-01 08:22:01 -0700549 case SpvOpShiftLeftLogical:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500550 return SkString("ShiftLeftLogical");
ethannicholasb3058bd2016-07-01 08:22:01 -0700551 case SpvOpBitwiseOr:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500552 return SkString("BitwiseOr");
ethannicholasb3058bd2016-07-01 08:22:01 -0700553 case SpvOpBitwiseXor:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500554 return SkString("BitwiseXor");
ethannicholasb3058bd2016-07-01 08:22:01 -0700555 case SpvOpBitwiseAnd:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500556 return SkString("BitwiseAnd");
ethannicholasb3058bd2016-07-01 08:22:01 -0700557 case SpvOpNot:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500558 return SkString("Not");
ethannicholasb3058bd2016-07-01 08:22:01 -0700559 case SpvOpBitFieldInsert:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500560 return SkString("BitFieldInsert");
ethannicholasb3058bd2016-07-01 08:22:01 -0700561 case SpvOpBitFieldSExtract:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500562 return SkString("BitFieldSExtract");
ethannicholasb3058bd2016-07-01 08:22:01 -0700563 case SpvOpBitFieldUExtract:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500564 return SkString("BitFieldUExtract");
ethannicholasb3058bd2016-07-01 08:22:01 -0700565 case SpvOpBitReverse:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500566 return SkString("BitReverse");
ethannicholasb3058bd2016-07-01 08:22:01 -0700567 case SpvOpBitCount:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500568 return SkString("BitCount");
ethannicholasb3058bd2016-07-01 08:22:01 -0700569 case SpvOpDPdx:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500570 return SkString("DPdx");
ethannicholasb3058bd2016-07-01 08:22:01 -0700571 case SpvOpDPdy:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500572 return SkString("DPdy");
ethannicholasb3058bd2016-07-01 08:22:01 -0700573 case SpvOpFwidth:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500574 return SkString("Fwidth");
ethannicholasb3058bd2016-07-01 08:22:01 -0700575 case SpvOpDPdxFine:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500576 return SkString("DPdxFine");
ethannicholasb3058bd2016-07-01 08:22:01 -0700577 case SpvOpDPdyFine:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500578 return SkString("DPdyFine");
ethannicholasb3058bd2016-07-01 08:22:01 -0700579 case SpvOpFwidthFine:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500580 return SkString("FwidthFine");
ethannicholasb3058bd2016-07-01 08:22:01 -0700581 case SpvOpDPdxCoarse:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500582 return SkString("DPdxCoarse");
ethannicholasb3058bd2016-07-01 08:22:01 -0700583 case SpvOpDPdyCoarse:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500584 return SkString("DPdyCoarse");
ethannicholasb3058bd2016-07-01 08:22:01 -0700585 case SpvOpFwidthCoarse:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500586 return SkString("FwidthCoarse");
ethannicholasb3058bd2016-07-01 08:22:01 -0700587 case SpvOpEmitVertex:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500588 return SkString("EmitVertex");
ethannicholasb3058bd2016-07-01 08:22:01 -0700589 case SpvOpEndPrimitive:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500590 return SkString("EndPrimitive");
ethannicholasb3058bd2016-07-01 08:22:01 -0700591 case SpvOpEmitStreamVertex:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500592 return SkString("EmitStreamVertex");
ethannicholasb3058bd2016-07-01 08:22:01 -0700593 case SpvOpEndStreamPrimitive:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500594 return SkString("EndStreamPrimitive");
ethannicholasb3058bd2016-07-01 08:22:01 -0700595 case SpvOpControlBarrier:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500596 return SkString("ControlBarrier");
ethannicholasb3058bd2016-07-01 08:22:01 -0700597 case SpvOpMemoryBarrier:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500598 return SkString("MemoryBarrier");
ethannicholasb3058bd2016-07-01 08:22:01 -0700599 case SpvOpAtomicLoad:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500600 return SkString("AtomicLoad");
ethannicholasb3058bd2016-07-01 08:22:01 -0700601 case SpvOpAtomicStore:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500602 return SkString("AtomicStore");
ethannicholasb3058bd2016-07-01 08:22:01 -0700603 case SpvOpAtomicExchange:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500604 return SkString("AtomicExchange");
ethannicholasb3058bd2016-07-01 08:22:01 -0700605 case SpvOpAtomicCompareExchange:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500606 return SkString("AtomicCompareExchange");
ethannicholasb3058bd2016-07-01 08:22:01 -0700607 case SpvOpAtomicCompareExchangeWeak:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500608 return SkString("AtomicCompareExchangeWeak");
ethannicholasb3058bd2016-07-01 08:22:01 -0700609 case SpvOpAtomicIIncrement:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500610 return SkString("AtomicIIncrement");
ethannicholasb3058bd2016-07-01 08:22:01 -0700611 case SpvOpAtomicIDecrement:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500612 return SkString("AtomicIDecrement");
ethannicholasb3058bd2016-07-01 08:22:01 -0700613 case SpvOpAtomicIAdd:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500614 return SkString("AtomicIAdd");
ethannicholasb3058bd2016-07-01 08:22:01 -0700615 case SpvOpAtomicISub:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500616 return SkString("AtomicISub");
ethannicholasb3058bd2016-07-01 08:22:01 -0700617 case SpvOpAtomicSMin:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500618 return SkString("AtomicSMin");
ethannicholasb3058bd2016-07-01 08:22:01 -0700619 case SpvOpAtomicUMin:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500620 return SkString("AtomicUMin");
ethannicholasb3058bd2016-07-01 08:22:01 -0700621 case SpvOpAtomicSMax:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500622 return SkString("AtomicSMax");
ethannicholasb3058bd2016-07-01 08:22:01 -0700623 case SpvOpAtomicUMax:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500624 return SkString("AtomicUMax");
ethannicholasb3058bd2016-07-01 08:22:01 -0700625 case SpvOpAtomicAnd:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500626 return SkString("AtomicAnd");
ethannicholasb3058bd2016-07-01 08:22:01 -0700627 case SpvOpAtomicOr:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500628 return SkString("AtomicOr");
ethannicholasb3058bd2016-07-01 08:22:01 -0700629 case SpvOpAtomicXor:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500630 return SkString("AtomicXor");
ethannicholasb3058bd2016-07-01 08:22:01 -0700631 case SpvOpPhi:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500632 return SkString("Phi");
ethannicholasb3058bd2016-07-01 08:22:01 -0700633 case SpvOpLoopMerge:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500634 return SkString("LoopMerge");
ethannicholasb3058bd2016-07-01 08:22:01 -0700635 case SpvOpSelectionMerge:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500636 return SkString("SelectionMerge");
ethannicholasb3058bd2016-07-01 08:22:01 -0700637 case SpvOpLabel:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500638 return SkString("Label");
ethannicholasb3058bd2016-07-01 08:22:01 -0700639 case SpvOpBranch:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500640 return SkString("Branch");
ethannicholasb3058bd2016-07-01 08:22:01 -0700641 case SpvOpBranchConditional:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500642 return SkString("BranchConditional");
ethannicholasb3058bd2016-07-01 08:22:01 -0700643 case SpvOpSwitch:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500644 return SkString("Switch");
ethannicholasb3058bd2016-07-01 08:22:01 -0700645 case SpvOpKill:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500646 return SkString("Kill");
ethannicholasb3058bd2016-07-01 08:22:01 -0700647 case SpvOpReturn:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500648 return SkString("Return");
ethannicholasb3058bd2016-07-01 08:22:01 -0700649 case SpvOpReturnValue:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500650 return SkString("ReturnValue");
ethannicholasb3058bd2016-07-01 08:22:01 -0700651 case SpvOpUnreachable:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500652 return SkString("Unreachable");
ethannicholasb3058bd2016-07-01 08:22:01 -0700653 case SpvOpLifetimeStart:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500654 return SkString("LifetimeStart");
ethannicholasb3058bd2016-07-01 08:22:01 -0700655 case SpvOpLifetimeStop:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500656 return SkString("LifetimeStop");
ethannicholasb3058bd2016-07-01 08:22:01 -0700657 case SpvOpGroupAsyncCopy:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500658 return SkString("GroupAsyncCopy");
ethannicholasb3058bd2016-07-01 08:22:01 -0700659 case SpvOpGroupWaitEvents:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500660 return SkString("GroupWaitEvents");
ethannicholasb3058bd2016-07-01 08:22:01 -0700661 case SpvOpGroupAll:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500662 return SkString("GroupAll");
ethannicholasb3058bd2016-07-01 08:22:01 -0700663 case SpvOpGroupAny:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500664 return SkString("GroupAny");
ethannicholasb3058bd2016-07-01 08:22:01 -0700665 case SpvOpGroupBroadcast:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500666 return SkString("GroupBroadcast");
ethannicholasb3058bd2016-07-01 08:22:01 -0700667 case SpvOpGroupIAdd:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500668 return SkString("GroupIAdd");
ethannicholasb3058bd2016-07-01 08:22:01 -0700669 case SpvOpGroupFAdd:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500670 return SkString("GroupFAdd");
ethannicholasb3058bd2016-07-01 08:22:01 -0700671 case SpvOpGroupFMin:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500672 return SkString("GroupFMin");
ethannicholasb3058bd2016-07-01 08:22:01 -0700673 case SpvOpGroupUMin:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500674 return SkString("GroupUMin");
ethannicholasb3058bd2016-07-01 08:22:01 -0700675 case SpvOpGroupSMin:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500676 return SkString("GroupSMin");
ethannicholasb3058bd2016-07-01 08:22:01 -0700677 case SpvOpGroupFMax:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500678 return SkString("GroupFMax");
ethannicholasb3058bd2016-07-01 08:22:01 -0700679 case SpvOpGroupUMax:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500680 return SkString("GroupUMax");
ethannicholasb3058bd2016-07-01 08:22:01 -0700681 case SpvOpGroupSMax:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500682 return SkString("GroupSMax");
ethannicholasb3058bd2016-07-01 08:22:01 -0700683 case SpvOpReadPipe:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500684 return SkString("ReadPipe");
ethannicholasb3058bd2016-07-01 08:22:01 -0700685 case SpvOpWritePipe:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500686 return SkString("WritePipe");
ethannicholasb3058bd2016-07-01 08:22:01 -0700687 case SpvOpReservedReadPipe:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500688 return SkString("ReservedReadPipe");
ethannicholasb3058bd2016-07-01 08:22:01 -0700689 case SpvOpReservedWritePipe:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500690 return SkString("ReservedWritePipe");
ethannicholasb3058bd2016-07-01 08:22:01 -0700691 case SpvOpReserveReadPipePackets:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500692 return SkString("ReserveReadPipePackets");
ethannicholasb3058bd2016-07-01 08:22:01 -0700693 case SpvOpReserveWritePipePackets:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500694 return SkString("ReserveWritePipePackets");
ethannicholasb3058bd2016-07-01 08:22:01 -0700695 case SpvOpCommitReadPipe:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500696 return SkString("CommitReadPipe");
ethannicholasb3058bd2016-07-01 08:22:01 -0700697 case SpvOpCommitWritePipe:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500698 return SkString("CommitWritePipe");
ethannicholasb3058bd2016-07-01 08:22:01 -0700699 case SpvOpIsValidReserveId:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500700 return SkString("IsValidReserveId");
ethannicholasb3058bd2016-07-01 08:22:01 -0700701 case SpvOpGetNumPipePackets:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500702 return SkString("GetNumPipePackets");
ethannicholasb3058bd2016-07-01 08:22:01 -0700703 case SpvOpGetMaxPipePackets:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500704 return SkString("GetMaxPipePackets");
ethannicholasb3058bd2016-07-01 08:22:01 -0700705 case SpvOpGroupReserveReadPipePackets:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500706 return SkString("GroupReserveReadPipePackets");
ethannicholasb3058bd2016-07-01 08:22:01 -0700707 case SpvOpGroupReserveWritePipePackets:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500708 return SkString("GroupReserveWritePipePackets");
ethannicholasb3058bd2016-07-01 08:22:01 -0700709 case SpvOpGroupCommitReadPipe:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500710 return SkString("GroupCommitReadPipe");
ethannicholasb3058bd2016-07-01 08:22:01 -0700711 case SpvOpGroupCommitWritePipe:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500712 return SkString("GroupCommitWritePipe");
ethannicholasb3058bd2016-07-01 08:22:01 -0700713 case SpvOpEnqueueMarker:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500714 return SkString("EnqueueMarker");
ethannicholasb3058bd2016-07-01 08:22:01 -0700715 case SpvOpEnqueueKernel:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500716 return SkString("EnqueueKernel");
ethannicholasb3058bd2016-07-01 08:22:01 -0700717 case SpvOpGetKernelNDrangeSubGroupCount:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500718 return SkString("GetKernelNDrangeSubGroupCount");
ethannicholasb3058bd2016-07-01 08:22:01 -0700719 case SpvOpGetKernelNDrangeMaxSubGroupSize:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500720 return SkString("GetKernelNDrangeMaxSubGroupSize");
ethannicholasb3058bd2016-07-01 08:22:01 -0700721 case SpvOpGetKernelWorkGroupSize:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500722 return SkString("GetKernelWorkGroupSize");
ethannicholasb3058bd2016-07-01 08:22:01 -0700723 case SpvOpGetKernelPreferredWorkGroupSizeMultiple:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500724 return SkString("GetKernelPreferredWorkGroupSizeMultiple");
ethannicholasb3058bd2016-07-01 08:22:01 -0700725 case SpvOpRetainEvent:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500726 return SkString("RetainEvent");
ethannicholasb3058bd2016-07-01 08:22:01 -0700727 case SpvOpReleaseEvent:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500728 return SkString("ReleaseEvent");
ethannicholasb3058bd2016-07-01 08:22:01 -0700729 case SpvOpCreateUserEvent:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500730 return SkString("CreateUserEvent");
ethannicholasb3058bd2016-07-01 08:22:01 -0700731 case SpvOpIsValidEvent:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500732 return SkString("IsValidEvent");
ethannicholasb3058bd2016-07-01 08:22:01 -0700733 case SpvOpSetUserEventStatus:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500734 return SkString("SetUserEventStatus");
ethannicholasb3058bd2016-07-01 08:22:01 -0700735 case SpvOpCaptureEventProfilingInfo:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500736 return SkString("CaptureEventProfilingInfo");
ethannicholasb3058bd2016-07-01 08:22:01 -0700737 case SpvOpGetDefaultQueue:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500738 return SkString("GetDefaultQueue");
ethannicholasb3058bd2016-07-01 08:22:01 -0700739 case SpvOpBuildNDRange:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500740 return SkString("BuildNDRange");
ethannicholasb3058bd2016-07-01 08:22:01 -0700741 case SpvOpImageSparseSampleImplicitLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500742 return SkString("ImageSparseSampleImplicitLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700743 case SpvOpImageSparseSampleExplicitLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500744 return SkString("ImageSparseSampleExplicitLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700745 case SpvOpImageSparseSampleDrefImplicitLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500746 return SkString("ImageSparseSampleDrefImplicitLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700747 case SpvOpImageSparseSampleDrefExplicitLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500748 return SkString("ImageSparseSampleDrefExplicitLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700749 case SpvOpImageSparseSampleProjImplicitLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500750 return SkString("ImageSparseSampleProjImplicitLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700751 case SpvOpImageSparseSampleProjExplicitLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500752 return SkString("ImageSparseSampleProjExplicitLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700753 case SpvOpImageSparseSampleProjDrefImplicitLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500754 return SkString("ImageSparseSampleProjDrefImplicitLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700755 case SpvOpImageSparseSampleProjDrefExplicitLod:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500756 return SkString("ImageSparseSampleProjDrefExplicitLod");
ethannicholasb3058bd2016-07-01 08:22:01 -0700757 case SpvOpImageSparseFetch:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500758 return SkString("ImageSparseFetch");
ethannicholasb3058bd2016-07-01 08:22:01 -0700759 case SpvOpImageSparseGather:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500760 return SkString("ImageSparseGather");
ethannicholasb3058bd2016-07-01 08:22:01 -0700761 case SpvOpImageSparseDrefGather:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500762 return SkString("ImageSparseDrefGather");
ethannicholasb3058bd2016-07-01 08:22:01 -0700763 case SpvOpImageSparseTexelsResident:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500764 return SkString("ImageSparseTexelsResident");
ethannicholasb3058bd2016-07-01 08:22:01 -0700765 case SpvOpNoLine:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500766 return SkString("NoLine");
ethannicholasb3058bd2016-07-01 08:22:01 -0700767 case SpvOpAtomicFlagTestAndSet:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500768 return SkString("AtomicFlagTestAndSet");
ethannicholasb3058bd2016-07-01 08:22:01 -0700769 case SpvOpAtomicFlagClear:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500770 return SkString("AtomicFlagClear");
ethannicholasb3058bd2016-07-01 08:22:01 -0700771 case SpvOpImageSparseRead:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500772 return SkString("ImageSparseRead");
ethannicholasb3058bd2016-07-01 08:22:01 -0700773 default:
774 ABORT("unsupported SPIR-V op");
775 }
776}
777#endif
778
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500779void SPIRVCodeGenerator::writeOpCode(SpvOp_ opCode, int length, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700780 ASSERT(opCode != SpvOpUndef);
781 switch (opCode) {
782 case SpvOpReturn: // fall through
783 case SpvOpReturnValue: // fall through
ethannicholas552882f2016-07-07 06:30:48 -0700784 case SpvOpKill: // fall through
ethannicholasb3058bd2016-07-01 08:22:01 -0700785 case SpvOpBranch: // fall through
786 case SpvOpBranchConditional:
787 ASSERT(fCurrentBlock);
788 fCurrentBlock = 0;
789 break;
790 case SpvOpConstant: // fall through
791 case SpvOpConstantTrue: // fall through
792 case SpvOpConstantFalse: // fall through
793 case SpvOpConstantComposite: // fall through
794 case SpvOpTypeVoid: // fall through
795 case SpvOpTypeInt: // fall through
796 case SpvOpTypeFloat: // fall through
797 case SpvOpTypeBool: // fall through
798 case SpvOpTypeVector: // fall through
799 case SpvOpTypeMatrix: // fall through
800 case SpvOpTypeArray: // fall through
801 case SpvOpTypePointer: // fall through
802 case SpvOpTypeFunction: // fall through
803 case SpvOpTypeRuntimeArray: // fall through
804 case SpvOpTypeStruct: // fall through
805 case SpvOpTypeImage: // fall through
806 case SpvOpTypeSampledImage: // fall through
807 case SpvOpVariable: // fall through
808 case SpvOpFunction: // fall through
809 case SpvOpFunctionParameter: // fall through
810 case SpvOpFunctionEnd: // fall through
811 case SpvOpExecutionMode: // fall through
812 case SpvOpMemoryModel: // fall through
813 case SpvOpCapability: // fall through
814 case SpvOpExtInstImport: // fall through
815 case SpvOpEntryPoint: // fall through
816 case SpvOpSource: // fall through
817 case SpvOpSourceExtension: // fall through
818 case SpvOpName: // fall through
819 case SpvOpMemberName: // fall through
820 case SpvOpDecorate: // fall through
821 case SpvOpMemberDecorate:
822 break;
823 default:
824 ASSERT(fCurrentBlock);
825 }
826#if SPIRV_DEBUG
827 out << std::endl << opcode_text(opCode) << " ";
828#else
829 this->writeWord((length << 16) | opCode, out);
830#endif
831}
832
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500833void SPIRVCodeGenerator::writeLabel(SpvId label, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700834 fCurrentBlock = label;
835 this->writeInstruction(SpvOpLabel, label, out);
836}
837
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500838void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700839 this->writeOpCode(opCode, 1, out);
840}
841
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500842void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700843 this->writeOpCode(opCode, 2, out);
844 this->writeWord(word1, out);
845}
846
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500847void SPIRVCodeGenerator::writeString(const char* string, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700848 size_t length = strlen(string);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500849 out.writeText(string);
ethannicholasb3058bd2016-07-01 08:22:01 -0700850 switch (length % 4) {
851 case 1:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500852 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700853 // fall through
854 case 2:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500855 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700856 // fall through
857 case 3:
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500858 out.write8(0);
ethannicholasb3058bd2016-07-01 08:22:01 -0700859 break;
860 default:
861 this->writeWord(0, out);
862 }
863}
864
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500865void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, const char* string, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700866 int32_t length = (int32_t) strlen(string);
867 this->writeOpCode(opCode, 1 + (length + 4) / 4, out);
868 this->writeString(string, out);
869}
870
871
872void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, const char* string,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500873 SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700874 int32_t length = (int32_t) strlen(string);
875 this->writeOpCode(opCode, 2 + (length + 4) / 4, out);
876 this->writeWord(word1, out);
877 this->writeString(string, out);
878}
879
880void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500881 const char* string, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700882 int32_t length = (int32_t) strlen(string);
883 this->writeOpCode(opCode, 3 + (length + 4) / 4, out);
884 this->writeWord(word1, out);
885 this->writeWord(word2, out);
886 this->writeString(string, out);
887}
888
889void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500890 SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700891 this->writeOpCode(opCode, 3, out);
892 this->writeWord(word1, out);
893 this->writeWord(word2, out);
894}
895
896void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500897 int32_t word3, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700898 this->writeOpCode(opCode, 4, out);
899 this->writeWord(word1, out);
900 this->writeWord(word2, out);
901 this->writeWord(word3, out);
902}
903
904void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500905 int32_t word3, int32_t word4, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700906 this->writeOpCode(opCode, 5, out);
907 this->writeWord(word1, out);
908 this->writeWord(word2, out);
909 this->writeWord(word3, out);
910 this->writeWord(word4, out);
911}
912
913void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
914 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500915 SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700916 this->writeOpCode(opCode, 6, out);
917 this->writeWord(word1, out);
918 this->writeWord(word2, out);
919 this->writeWord(word3, out);
920 this->writeWord(word4, out);
921 this->writeWord(word5, out);
922}
923
924void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
925 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500926 int32_t word6, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700927 this->writeOpCode(opCode, 7, out);
928 this->writeWord(word1, out);
929 this->writeWord(word2, out);
930 this->writeWord(word3, out);
931 this->writeWord(word4, out);
932 this->writeWord(word5, out);
933 this->writeWord(word6, out);
934}
935
936void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
937 int32_t word3, int32_t word4, int32_t word5,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500938 int32_t word6, int32_t word7, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700939 this->writeOpCode(opCode, 8, out);
940 this->writeWord(word1, out);
941 this->writeWord(word2, out);
942 this->writeWord(word3, out);
943 this->writeWord(word4, out);
944 this->writeWord(word5, out);
945 this->writeWord(word6, out);
946 this->writeWord(word7, out);
947}
948
949void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
950 int32_t word3, int32_t word4, int32_t word5,
951 int32_t word6, int32_t word7, int32_t word8,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500952 SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700953 this->writeOpCode(opCode, 9, out);
954 this->writeWord(word1, out);
955 this->writeWord(word2, out);
956 this->writeWord(word3, out);
957 this->writeWord(word4, out);
958 this->writeWord(word5, out);
959 this->writeWord(word6, out);
960 this->writeWord(word7, out);
961 this->writeWord(word8, out);
962}
963
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500964void SPIRVCodeGenerator::writeCapabilities(SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700965 for (uint64_t i = 0, bit = 1; i <= kLast_Capability; i++, bit <<= 1) {
966 if (fCapabilities & bit) {
967 this->writeInstruction(SpvOpCapability, (SpvId) i, out);
968 }
969 }
970}
971
972SpvId SPIRVCodeGenerator::nextId() {
973 return fIdCount++;
974}
975
egdaniel988283c2016-11-16 07:29:51 -0800976void SPIRVCodeGenerator::writeStruct(const Type& type, SpvId resultId) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700977 this->writeInstruction(SpvOpName, resultId, type.name().c_str(), fNameBuffer);
978 // go ahead and write all of the field types, so we don't inadvertently write them while we're
979 // in the middle of writing the struct instruction
980 std::vector<SpvId> types;
981 for (const auto& f : type.fields()) {
egdaniel988283c2016-11-16 07:29:51 -0800982 types.push_back(this->getType(*f.fType));
ethannicholasb3058bd2016-07-01 08:22:01 -0700983 }
984 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
985 this->writeWord(resultId, fConstantBuffer);
986 for (SpvId id : types) {
987 this->writeWord(id, fConstantBuffer);
988 }
989 size_t offset = 0;
990 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
egdaniel988283c2016-11-16 07:29:51 -0800991 size_t size = type.fields()[i].fType->size();
992 size_t alignment = type.fields()[i].fType->alignment();
ethannicholasb3058bd2016-07-01 08:22:01 -0700993 size_t mod = offset % alignment;
994 if (mod != 0) {
995 offset += alignment - mod;
996 }
997 this->writeInstruction(SpvOpMemberName, resultId, i, type.fields()[i].fName.c_str(),
998 fNameBuffer);
999 this->writeLayout(type.fields()[i].fModifiers.fLayout, resultId, i);
1000 if (type.fields()[i].fModifiers.fLayout.fBuiltin < 0) {
1001 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
1002 (SpvId) offset, fDecorationBuffer);
1003 }
ethannicholas0730be72016-09-01 07:59:02 -07001004 if (type.fields()[i].fType->kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001005 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
1006 fDecorationBuffer);
1007 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
egdaniel988283c2016-11-16 07:29:51 -08001008 (SpvId) type.fields()[i].fType->stride(), fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001009 }
1010 offset += size;
ethannicholas0730be72016-09-01 07:59:02 -07001011 Type::Kind kind = type.fields()[i].fType->kind();
ethannicholasb3058bd2016-07-01 08:22:01 -07001012 if ((kind == Type::kArray_Kind || kind == Type::kStruct_Kind) && offset % alignment != 0) {
1013 offset += alignment - offset % alignment;
1014 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001015 }
1016}
1017
1018SpvId SPIRVCodeGenerator::getType(const Type& type) {
egdaniel988283c2016-11-16 07:29:51 -08001019 auto entry = fTypeMap.find(type.name());
ethannicholasb3058bd2016-07-01 08:22:01 -07001020 if (entry == fTypeMap.end()) {
1021 SpvId result = this->nextId();
1022 switch (type.kind()) {
1023 case Type::kScalar_Kind:
ethannicholasd598f792016-07-25 10:08:54 -07001024 if (type == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001025 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001026 } else if (type == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001027 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001028 } else if (type == *fContext.fUInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001029 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001030 } else if (type == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001031 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001032 } else if (type == *fContext.fDouble_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001033 this->writeInstruction(SpvOpTypeFloat, result, 64, fConstantBuffer);
1034 } else {
1035 ASSERT(false);
1036 }
1037 break;
1038 case Type::kVector_Kind:
1039 this->writeInstruction(SpvOpTypeVector, result,
egdaniel988283c2016-11-16 07:29:51 -08001040 this->getType(type.componentType()),
ethannicholasb3058bd2016-07-01 08:22:01 -07001041 type.columns(), fConstantBuffer);
1042 break;
1043 case Type::kMatrix_Kind:
ethannicholasd598f792016-07-25 10:08:54 -07001044 this->writeInstruction(SpvOpTypeMatrix, result,
egdaniel988283c2016-11-16 07:29:51 -08001045 this->getType(index_type(fContext, type)),
ethannicholasb3058bd2016-07-01 08:22:01 -07001046 type.columns(), fConstantBuffer);
1047 break;
1048 case Type::kStruct_Kind:
egdaniel988283c2016-11-16 07:29:51 -08001049 this->writeStruct(type, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001050 break;
1051 case Type::kArray_Kind: {
1052 if (type.columns() > 0) {
ethannicholasd598f792016-07-25 10:08:54 -07001053 IntLiteral count(fContext, Position(), type.columns());
ethannicholasb3058bd2016-07-01 08:22:01 -07001054 this->writeInstruction(SpvOpTypeArray, result,
egdaniel988283c2016-11-16 07:29:51 -08001055 this->getType(type.componentType()),
ethannicholasb3058bd2016-07-01 08:22:01 -07001056 this->writeIntLiteral(count), fConstantBuffer);
1057 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
egdaniel988283c2016-11-16 07:29:51 -08001058 (int32_t) type.stride(), fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001059 } else {
1060 ABORT("runtime-sized arrays are not yet supported");
1061 this->writeInstruction(SpvOpTypeRuntimeArray, result,
egdaniel988283c2016-11-16 07:29:51 -08001062 this->getType(type.componentType()), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001063 }
1064 break;
1065 }
1066 case Type::kSampler_Kind: {
1067 SpvId image = this->nextId();
egdaniel988283c2016-11-16 07:29:51 -08001068 this->writeInstruction(SpvOpTypeImage, image, this->getType(*fContext.fFloat_Type),
ethannicholasb3058bd2016-07-01 08:22:01 -07001069 type.dimensions(), type.isDepth(), type.isArrayed(),
1070 type.isMultisampled(), type.isSampled(),
1071 SpvImageFormatUnknown, fConstantBuffer);
1072 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
1073 break;
1074 }
1075 default:
ethannicholasd598f792016-07-25 10:08:54 -07001076 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001077 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
1078 } else {
1079 ABORT("invalid type: %s", type.description().c_str());
1080 }
1081 }
egdaniel988283c2016-11-16 07:29:51 -08001082 fTypeMap[type.name()] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001083 return result;
1084 }
1085 return entry->second;
1086}
1087
ethannicholasd598f792016-07-25 10:08:54 -07001088SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001089 SkString key = function.fReturnType.description() + "(";
1090 SkString separator;
ethannicholasd598f792016-07-25 10:08:54 -07001091 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001092 key += separator;
1093 separator = ", ";
ethannicholasd598f792016-07-25 10:08:54 -07001094 key += function.fParameters[i]->fType.description();
ethannicholasb3058bd2016-07-01 08:22:01 -07001095 }
1096 key += ")";
1097 auto entry = fTypeMap.find(key);
1098 if (entry == fTypeMap.end()) {
1099 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001100 int32_t length = 3 + (int32_t) function.fParameters.size();
1101 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001102 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -07001103 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001104 // glslang seems to treat all function arguments as pointers whether they need to be or
1105 // not. I was initially puzzled by this until I ran bizarre failures with certain
1106 // patterns of function calls and control constructs, as exemplified by this minimal
1107 // failure case:
1108 //
1109 // void sphere(float x) {
1110 // }
1111 //
1112 // void map() {
1113 // sphere(1.0);
1114 // }
1115 //
1116 // void main() {
1117 // for (int i = 0; i < 1; i++) {
1118 // map();
1119 // }
1120 // }
1121 //
1122 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
1123 // crashes. Making it take a float* and storing the argument in a temporary variable,
1124 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
1125 // the spec makes this make sense.
1126// if (is_out(function->fParameters[i])) {
ethannicholasd598f792016-07-25 10:08:54 -07001127 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -07001128 SpvStorageClassFunction));
1129// } else {
ethannicholasd598f792016-07-25 10:08:54 -07001130// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07001131// }
1132 }
1133 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
1134 this->writeWord(result, fConstantBuffer);
1135 this->writeWord(returnType, fConstantBuffer);
1136 for (SpvId id : parameterTypes) {
1137 this->writeWord(id, fConstantBuffer);
1138 }
1139 fTypeMap[key] = result;
1140 return result;
1141 }
1142 return entry->second;
1143}
1144
egdaniel988283c2016-11-16 07:29:51 -08001145SpvId SPIRVCodeGenerator::getPointerType(const Type& type,
ethannicholasb3058bd2016-07-01 08:22:01 -07001146 SpvStorageClass_ storageClass) {
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001147 SkString key = type.description() + "*" + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -07001148 auto entry = fTypeMap.find(key);
1149 if (entry == fTypeMap.end()) {
1150 SpvId result = this->nextId();
1151 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -07001152 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001153 fTypeMap[key] = result;
1154 return result;
1155 }
1156 return entry->second;
1157}
1158
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001159SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001160 switch (expr.fKind) {
1161 case Expression::kBinary_Kind:
1162 return this->writeBinaryExpression((BinaryExpression&) expr, out);
1163 case Expression::kBoolLiteral_Kind:
1164 return this->writeBoolLiteral((BoolLiteral&) expr);
1165 case Expression::kConstructor_Kind:
1166 return this->writeConstructor((Constructor&) expr, out);
1167 case Expression::kIntLiteral_Kind:
1168 return this->writeIntLiteral((IntLiteral&) expr);
1169 case Expression::kFieldAccess_Kind:
1170 return this->writeFieldAccess(((FieldAccess&) expr), out);
1171 case Expression::kFloatLiteral_Kind:
1172 return this->writeFloatLiteral(((FloatLiteral&) expr));
1173 case Expression::kFunctionCall_Kind:
1174 return this->writeFunctionCall((FunctionCall&) expr, out);
1175 case Expression::kPrefix_Kind:
1176 return this->writePrefixExpression((PrefixExpression&) expr, out);
1177 case Expression::kPostfix_Kind:
1178 return this->writePostfixExpression((PostfixExpression&) expr, out);
1179 case Expression::kSwizzle_Kind:
1180 return this->writeSwizzle((Swizzle&) expr, out);
1181 case Expression::kVariableReference_Kind:
1182 return this->writeVariableReference((VariableReference&) expr, out);
1183 case Expression::kTernary_Kind:
1184 return this->writeTernaryExpression((TernaryExpression&) expr, out);
1185 case Expression::kIndex_Kind:
1186 return this->writeIndexExpression((IndexExpression&) expr, out);
1187 default:
1188 ABORT("unsupported expression: %s", expr.description().c_str());
1189 }
1190 return -1;
1191}
1192
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001193SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, SkWStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001194 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
ethannicholasb3058bd2016-07-01 08:22:01 -07001195 ASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasd598f792016-07-25 10:08:54 -07001196 const Type& type = c.fArguments[0]->fType;
ethannicholasb3058bd2016-07-01 08:22:01 -07001197 int32_t intrinsicId;
ethannicholasd598f792016-07-25 10:08:54 -07001198 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001199 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasd598f792016-07-25 10:08:54 -07001200 } else if (is_signed(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001201 intrinsicId = std::get<2>(intrinsic->second);
ethannicholasd598f792016-07-25 10:08:54 -07001202 } else if (is_unsigned(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001203 intrinsicId = std::get<3>(intrinsic->second);
ethannicholasd598f792016-07-25 10:08:54 -07001204 } else if (is_bool(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001205 intrinsicId = std::get<4>(intrinsic->second);
1206 } else {
1207 ABORT("invalid call %s, cannot operate on '%s'", c.description().c_str(),
ethannicholasd598f792016-07-25 10:08:54 -07001208 type.description().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07001209 }
1210 switch (std::get<0>(intrinsic->second)) {
1211 case kGLSL_STD_450_IntrinsicKind: {
1212 SpvId result = this->nextId();
1213 std::vector<SpvId> arguments;
1214 for (size_t i = 0; i < c.fArguments.size(); i++) {
1215 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1216 }
1217 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001218 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001219 this->writeWord(result, out);
1220 this->writeWord(fGLSLExtendedInstructions, out);
1221 this->writeWord(intrinsicId, out);
1222 for (SpvId id : arguments) {
1223 this->writeWord(id, out);
1224 }
1225 return result;
1226 }
1227 case kSPIRV_IntrinsicKind: {
1228 SpvId result = this->nextId();
1229 std::vector<SpvId> arguments;
1230 for (size_t i = 0; i < c.fArguments.size(); i++) {
1231 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1232 }
1233 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001234 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001235 this->writeWord(result, out);
1236 for (SpvId id : arguments) {
1237 this->writeWord(id, out);
1238 }
1239 return result;
1240 }
1241 case kSpecial_IntrinsicKind:
1242 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
1243 default:
1244 ABORT("unsupported intrinsic kind");
1245 }
1246}
1247
ethannicholasf789b382016-08-03 12:43:36 -07001248SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001249 SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001250 SpvId result = this->nextId();
1251 switch (kind) {
1252 case kAtan_SpecialIntrinsic: {
1253 std::vector<SpvId> arguments;
1254 for (size_t i = 0; i < c.fArguments.size(); i++) {
1255 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1256 }
1257 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001258 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001259 this->writeWord(result, out);
1260 this->writeWord(fGLSLExtendedInstructions, out);
1261 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
1262 for (SpvId id : arguments) {
1263 this->writeWord(id, out);
1264 }
1265 return result;
1266 }
1267 case kTexture_SpecialIntrinsic: {
ethannicholasd598f792016-07-25 10:08:54 -07001268 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001269 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
1270 SpvId uv = this->writeExpression(*c.fArguments[1], out);
1271 if (c.fArguments.size() == 3) {
1272 this->writeInstruction(SpvOpImageSampleImplicitLod, type, result, sampler, uv,
1273 SpvImageOperandsBiasMask,
1274 this->writeExpression(*c.fArguments[2], out),
1275 out);
1276 } else {
1277 ASSERT(c.fArguments.size() == 2);
1278 this->writeInstruction(SpvOpImageSampleImplicitLod, type, result, sampler, uv, out);
1279 }
1280 break;
1281 }
1282 case kTextureProj_SpecialIntrinsic: {
ethannicholasd598f792016-07-25 10:08:54 -07001283 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001284 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
1285 SpvId uv = this->writeExpression(*c.fArguments[1], out);
1286 if (c.fArguments.size() == 3) {
1287 this->writeInstruction(SpvOpImageSampleProjImplicitLod, type, result, sampler, uv,
1288 SpvImageOperandsBiasMask,
1289 this->writeExpression(*c.fArguments[2], out),
1290 out);
1291 } else {
1292 ASSERT(c.fArguments.size() == 2);
1293 this->writeInstruction(SpvOpImageSampleProjImplicitLod, type, result, sampler, uv,
1294 out);
1295 }
1296 break;
1297 }
1298 case kTexture2D_SpecialIntrinsic: {
1299 SpvId img = this->writeExpression(*c.fArguments[0], out);
1300 SpvId coords = this->writeExpression(*c.fArguments[1], out);
1301 this->writeInstruction(SpvOpImageSampleImplicitLod,
ethannicholasd598f792016-07-25 10:08:54 -07001302 this->getType(c.fType),
ethannicholasb3058bd2016-07-01 08:22:01 -07001303 result,
1304 img,
1305 coords,
1306 out);
1307 break;
1308 }
1309 }
1310 return result;
1311}
1312
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001313SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, SkWStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001314 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07001315 if (entry == fFunctionMap.end()) {
1316 return this->writeIntrinsicCall(c, out);
1317 }
1318 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
1319 std::vector<std::tuple<SpvId, SpvId, std::unique_ptr<LValue>>> lvalues;
1320 std::vector<SpvId> arguments;
1321 for (size_t i = 0; i < c.fArguments.size(); i++) {
1322 // id of temporary variable that we will use to hold this argument, or 0 if it is being
1323 // passed directly
1324 SpvId tmpVar;
1325 // if we need a temporary var to store this argument, this is the value to store in the var
1326 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -07001327 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001328 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
1329 SpvId ptr = lv->getPointer();
1330 if (ptr) {
1331 arguments.push_back(ptr);
1332 continue;
1333 } else {
1334 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1335 // copy it into a temp, call the function, read the value out of the temp, and then
1336 // update the lvalue.
1337 tmpValueId = lv->load(out);
1338 tmpVar = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001339 lvalues.push_back(std::make_tuple(tmpVar, this->getType(c.fArguments[i]->fType),
ethannicholasb3058bd2016-07-01 08:22:01 -07001340 std::move(lv)));
1341 }
1342 } else {
1343 // see getFunctionType for an explanation of why we're always using pointer parameters
1344 tmpValueId = this->writeExpression(*c.fArguments[i], out);
1345 tmpVar = this->nextId();
1346 }
1347 this->writeInstruction(SpvOpVariable,
1348 this->getPointerType(c.fArguments[i]->fType,
1349 SpvStorageClassFunction),
1350 tmpVar,
1351 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001352 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001353 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1354 arguments.push_back(tmpVar);
1355 }
1356 SpvId result = this->nextId();
1357 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001358 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001359 this->writeWord(result, out);
1360 this->writeWord(entry->second, out);
1361 for (SpvId id : arguments) {
1362 this->writeWord(id, out);
1363 }
1364 // now that the call is complete, we may need to update some lvalues with the new values of out
1365 // arguments
1366 for (const auto& tuple : lvalues) {
1367 SpvId load = this->nextId();
1368 this->writeInstruction(SpvOpLoad, std::get<1>(tuple), load, std::get<0>(tuple), out);
1369 std::get<2>(tuple)->store(load, out);
1370 }
1371 return result;
1372}
1373
ethannicholasf789b382016-08-03 12:43:36 -07001374SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
ethannicholasd598f792016-07-25 10:08:54 -07001375 ASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001376 SpvId result = this->nextId();
1377 std::vector<SpvId> arguments;
1378 for (size_t i = 0; i < c.fArguments.size(); i++) {
1379 arguments.push_back(this->writeExpression(*c.fArguments[i], fConstantBuffer));
1380 }
ethannicholasd598f792016-07-25 10:08:54 -07001381 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001382 if (c.fArguments.size() == 1) {
1383 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001384 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001385 this->writeWord(type, fConstantBuffer);
1386 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001387 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001388 this->writeWord(arguments[0], fConstantBuffer);
1389 }
1390 } else {
1391 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
1392 fConstantBuffer);
1393 this->writeWord(type, fConstantBuffer);
1394 this->writeWord(result, fConstantBuffer);
1395 for (SpvId id : arguments) {
1396 this->writeWord(id, fConstantBuffer);
1397 }
1398 }
1399 return result;
1400}
1401
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001402SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, SkWStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001403 ASSERT(c.fType == *fContext.fFloat_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001404 ASSERT(c.fArguments.size() == 1);
ethannicholasd598f792016-07-25 10:08:54 -07001405 ASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001406 SpvId result = this->nextId();
1407 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
ethannicholasd598f792016-07-25 10:08:54 -07001408 if (c.fArguments[0]->fType == *fContext.fInt_Type) {
1409 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001410 out);
ethannicholasd598f792016-07-25 10:08:54 -07001411 } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) {
1412 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001413 out);
ethannicholasd598f792016-07-25 10:08:54 -07001414 } else if (c.fArguments[0]->fType == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001415 return parameter;
1416 }
1417 return result;
1418}
1419
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001420SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, SkWStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001421 ASSERT(c.fType == *fContext.fInt_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001422 ASSERT(c.fArguments.size() == 1);
ethannicholasd598f792016-07-25 10:08:54 -07001423 ASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001424 SpvId result = this->nextId();
1425 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
ethannicholasd598f792016-07-25 10:08:54 -07001426 if (c.fArguments[0]->fType == *fContext.fFloat_Type) {
1427 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001428 out);
ethannicholasd598f792016-07-25 10:08:54 -07001429 } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) {
1430 this->writeInstruction(SpvOpSatConvertUToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001431 out);
ethannicholasd598f792016-07-25 10:08:54 -07001432 } else if (c.fArguments[0]->fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001433 return parameter;
1434 }
1435 return result;
1436}
1437
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001438SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, SkWStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001439 ASSERT(c.fType.kind() == Type::kMatrix_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001440 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1441 // an instruction
1442 std::vector<SpvId> arguments;
1443 for (size_t i = 0; i < c.fArguments.size(); i++) {
1444 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1445 }
1446 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001447 int rows = c.fType.rows();
1448 int columns = c.fType.columns();
ethannicholasb3058bd2016-07-01 08:22:01 -07001449 // FIXME this won't work to create a matrix from another matrix
1450 if (arguments.size() == 1) {
1451 // with a single argument, a matrix will have all of its diagonal entries equal to the
1452 // argument and its other values equal to zero
1453 // FIXME this won't work for int matrices
ethannicholasd598f792016-07-25 10:08:54 -07001454 FloatLiteral zero(fContext, Position(), 0);
ethannicholasb3058bd2016-07-01 08:22:01 -07001455 SpvId zeroId = this->writeFloatLiteral(zero);
1456 std::vector<SpvId> columnIds;
1457 for (int column = 0; column < columns; column++) {
ethannicholasd598f792016-07-25 10:08:54 -07001458 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.rows(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001459 out);
ethannicholasd598f792016-07-25 10:08:54 -07001460 this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows, 1)),
1461 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001462 SpvId columnId = this->nextId();
1463 this->writeWord(columnId, out);
1464 columnIds.push_back(columnId);
ethannicholasd598f792016-07-25 10:08:54 -07001465 for (int row = 0; row < c.fType.columns(); row++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001466 this->writeWord(row == column ? arguments[0] : zeroId, out);
1467 }
1468 }
1469 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns,
1470 out);
ethannicholasd598f792016-07-25 10:08:54 -07001471 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001472 this->writeWord(result, out);
1473 for (SpvId id : columnIds) {
1474 this->writeWord(id, out);
1475 }
1476 } else {
1477 std::vector<SpvId> columnIds;
1478 int currentCount = 0;
1479 for (size_t i = 0; i < arguments.size(); i++) {
ethannicholasd598f792016-07-25 10:08:54 -07001480 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001481 ASSERT(currentCount == 0);
1482 columnIds.push_back(arguments[i]);
1483 currentCount = 0;
1484 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001485 ASSERT(c.fArguments[i]->fType.kind() == Type::kScalar_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001486 if (currentCount == 0) {
ethannicholasd598f792016-07-25 10:08:54 -07001487 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.rows(), out);
1488 this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows,
1489 1)),
ethannicholasb3058bd2016-07-01 08:22:01 -07001490 out);
1491 SpvId id = this->nextId();
1492 this->writeWord(id, out);
1493 columnIds.push_back(id);
1494 }
1495 this->writeWord(arguments[i], out);
1496 currentCount = (currentCount + 1) % rows;
1497 }
1498 }
1499 ASSERT(columnIds.size() == (size_t) columns);
1500 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001501 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001502 this->writeWord(result, out);
1503 for (SpvId id : columnIds) {
1504 this->writeWord(id, out);
1505 }
1506 }
1507 return result;
1508}
1509
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001510SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, SkWStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001511 ASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001512 if (c.isConstant()) {
1513 return this->writeConstantVector(c);
1514 }
1515 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1516 // an instruction
1517 std::vector<SpvId> arguments;
1518 for (size_t i = 0; i < c.fArguments.size(); i++) {
1519 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1520 }
1521 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001522 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1523 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1524 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001525 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001526 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001527 this->writeWord(arguments[0], out);
1528 }
1529 } else {
1530 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001531 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001532 this->writeWord(result, out);
1533 for (SpvId id : arguments) {
1534 this->writeWord(id, out);
1535 }
1536 }
1537 return result;
1538}
1539
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001540SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, SkWStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001541 if (c.fType == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001542 return this->writeFloatConstructor(c, out);
ethannicholasd598f792016-07-25 10:08:54 -07001543 } else if (c.fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001544 return this->writeIntConstructor(c, out);
1545 }
ethannicholasd598f792016-07-25 10:08:54 -07001546 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001547 case Type::kVector_Kind:
1548 return this->writeVectorConstructor(c, out);
1549 case Type::kMatrix_Kind:
1550 return this->writeMatrixConstructor(c, out);
1551 default:
1552 ABORT("unsupported constructor: %s", c.description().c_str());
1553 }
1554}
1555
1556SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1557 if (modifiers.fFlags & Modifiers::kIn_Flag) {
1558 return SpvStorageClassInput;
1559 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
1560 return SpvStorageClassOutput;
1561 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
1562 return SpvStorageClassUniform;
1563 } else {
1564 return SpvStorageClassFunction;
1565 }
1566}
1567
ethannicholasf789b382016-08-03 12:43:36 -07001568SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001569 switch (expr.fKind) {
1570 case Expression::kVariableReference_Kind:
ethannicholasd598f792016-07-25 10:08:54 -07001571 return get_storage_class(((VariableReference&) expr).fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07001572 case Expression::kFieldAccess_Kind:
1573 return get_storage_class(*((FieldAccess&) expr).fBase);
1574 case Expression::kIndex_Kind:
1575 return get_storage_class(*((IndexExpression&) expr).fBase);
1576 default:
1577 return SpvStorageClassFunction;
1578 }
1579}
1580
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001581std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001582 std::vector<SpvId> chain;
1583 switch (expr.fKind) {
1584 case Expression::kIndex_Kind: {
1585 IndexExpression& indexExpr = (IndexExpression&) expr;
1586 chain = this->getAccessChain(*indexExpr.fBase, out);
1587 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1588 break;
1589 }
1590 case Expression::kFieldAccess_Kind: {
1591 FieldAccess& fieldExpr = (FieldAccess&) expr;
1592 chain = this->getAccessChain(*fieldExpr.fBase, out);
ethannicholasd598f792016-07-25 10:08:54 -07001593 IntLiteral index(fContext, Position(), fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001594 chain.push_back(this->writeIntLiteral(index));
1595 break;
1596 }
1597 default:
1598 chain.push_back(this->getLValue(expr, out)->getPointer());
1599 }
1600 return chain;
1601}
1602
1603class PointerLValue : public SPIRVCodeGenerator::LValue {
1604public:
1605 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type)
1606 : fGen(gen)
1607 , fPointer(pointer)
1608 , fType(type) {}
1609
1610 virtual SpvId getPointer() override {
1611 return fPointer;
1612 }
1613
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001614 virtual SpvId load(SkWStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001615 SpvId result = fGen.nextId();
1616 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
1617 return result;
1618 }
1619
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001620 virtual void store(SpvId value, SkWStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001621 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1622 }
1623
1624private:
1625 SPIRVCodeGenerator& fGen;
1626 const SpvId fPointer;
1627 const SpvId fType;
1628};
1629
1630class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1631public:
1632 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
1633 const Type& baseType, const Type& swizzleType)
1634 : fGen(gen)
1635 , fVecPointer(vecPointer)
1636 , fComponents(components)
1637 , fBaseType(baseType)
1638 , fSwizzleType(swizzleType) {}
1639
1640 virtual SpvId getPointer() override {
1641 return 0;
1642 }
1643
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001644 virtual SpvId load(SkWStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001645 SpvId base = fGen.nextId();
1646 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1647 SpvId result = fGen.nextId();
1648 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1649 fGen.writeWord(fGen.getType(fSwizzleType), out);
1650 fGen.writeWord(result, out);
1651 fGen.writeWord(base, out);
1652 fGen.writeWord(base, out);
1653 for (int component : fComponents) {
1654 fGen.writeWord(component, out);
1655 }
1656 return result;
1657 }
1658
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001659 virtual void store(SpvId value, SkWStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001660 // use OpVectorShuffle to mix and match the vector components. We effectively create
1661 // a virtual vector out of the concatenation of the left and right vectors, and then
1662 // select components from this virtual vector to make the result vector. For
1663 // instance, given:
1664 // vec3 L = ...;
1665 // vec3 R = ...;
1666 // L.xz = R.xy;
1667 // we end up with the virtual vector (L.x, L.y, L.z, R.x, R.y, R.z). Then we want
1668 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1669 // (3, 1, 4).
1670 SpvId base = fGen.nextId();
1671 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1672 SpvId shuffle = fGen.nextId();
1673 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1674 fGen.writeWord(fGen.getType(fBaseType), out);
1675 fGen.writeWord(shuffle, out);
1676 fGen.writeWord(base, out);
1677 fGen.writeWord(value, out);
1678 for (int i = 0; i < fBaseType.columns(); i++) {
1679 // current offset into the virtual vector, defaults to pulling the unmodified
1680 // value from the left side
1681 int offset = i;
1682 // check to see if we are writing this component
1683 for (size_t j = 0; j < fComponents.size(); j++) {
1684 if (fComponents[j] == i) {
1685 // we're writing to this component, so adjust the offset to pull from
1686 // the correct component of the right side instead of preserving the
1687 // value from the left
1688 offset = (int) (j + fBaseType.columns());
1689 break;
1690 }
1691 }
1692 fGen.writeWord(offset, out);
1693 }
1694 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1695 }
1696
1697private:
1698 SPIRVCodeGenerator& fGen;
1699 const SpvId fVecPointer;
1700 const std::vector<int>& fComponents;
1701 const Type& fBaseType;
1702 const Type& fSwizzleType;
1703};
1704
ethannicholasf789b382016-08-03 12:43:36 -07001705std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001706 SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001707 switch (expr.fKind) {
1708 case Expression::kVariableReference_Kind: {
ethannicholasd598f792016-07-25 10:08:54 -07001709 const Variable& var = ((VariableReference&) expr).fVariable;
1710 auto entry = fVariableMap.find(&var);
ethannicholasb3058bd2016-07-01 08:22:01 -07001711 ASSERT(entry != fVariableMap.end());
1712 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1713 *this,
1714 entry->second,
ethannicholasd598f792016-07-25 10:08:54 -07001715 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001716 }
1717 case Expression::kIndex_Kind: // fall through
1718 case Expression::kFieldAccess_Kind: {
1719 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1720 SpvId member = this->nextId();
1721 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
1722 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
1723 this->writeWord(member, out);
1724 for (SpvId idx : chain) {
1725 this->writeWord(idx, out);
1726 }
1727 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1728 *this,
1729 member,
ethannicholasd598f792016-07-25 10:08:54 -07001730 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001731 }
1732
1733 case Expression::kSwizzle_Kind: {
1734 Swizzle& swizzle = (Swizzle&) expr;
1735 size_t count = swizzle.fComponents.size();
1736 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
1737 ASSERT(base);
1738 if (count == 1) {
ethannicholasd598f792016-07-25 10:08:54 -07001739 IntLiteral index(fContext, Position(), swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001740 SpvId member = this->nextId();
1741 this->writeInstruction(SpvOpAccessChain,
1742 this->getPointerType(swizzle.fType,
1743 get_storage_class(*swizzle.fBase)),
1744 member,
1745 base,
1746 this->writeIntLiteral(index),
1747 out);
1748 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1749 *this,
1750 member,
ethannicholasd598f792016-07-25 10:08:54 -07001751 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001752 } else {
1753 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
1754 *this,
1755 base,
1756 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001757 swizzle.fBase->fType,
1758 expr.fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07001759 }
1760 }
1761
1762 default:
1763 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
1764 // to the need to store values in temporary variables during function calls (see
1765 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1766 // caught by IRGenerator
1767 SpvId result = this->nextId();
1768 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001769 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1770 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001771 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1772 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1773 *this,
1774 result,
ethannicholasd598f792016-07-25 10:08:54 -07001775 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001776 }
1777}
1778
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001779SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, SkWStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001780 auto entry = fVariableMap.find(&ref.fVariable);
ethannicholasb3058bd2016-07-01 08:22:01 -07001781 ASSERT(entry != fVariableMap.end());
1782 SpvId var = entry->second;
1783 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001784 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001785 return result;
1786}
1787
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001788SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001789 return getLValue(expr, out)->load(out);
1790}
1791
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001792SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001793 return getLValue(f, out)->load(out);
1794}
1795
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001796SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001797 SpvId base = this->writeExpression(*swizzle.fBase, out);
1798 SpvId result = this->nextId();
1799 size_t count = swizzle.fComponents.size();
1800 if (count == 1) {
ethannicholasd598f792016-07-25 10:08:54 -07001801 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
ethannicholasb3058bd2016-07-01 08:22:01 -07001802 swizzle.fComponents[0], out);
1803 } else {
1804 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
ethannicholasd598f792016-07-25 10:08:54 -07001805 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001806 this->writeWord(result, out);
1807 this->writeWord(base, out);
1808 this->writeWord(base, out);
1809 for (int component : swizzle.fComponents) {
1810 this->writeWord(component, out);
1811 }
1812 }
1813 return result;
1814}
1815
1816SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1817 const Type& operandType, SpvId lhs,
1818 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001819 SpvOp_ ifUInt, SpvOp_ ifBool, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001820 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001821 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001822 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001823 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001824 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001825 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001826 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001827 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001828 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
1829 } else {
1830 ABORT("invalid operandType: %s", operandType.description().c_str());
1831 }
1832 return result;
1833}
1834
1835bool is_assignment(Token::Kind op) {
1836 switch (op) {
1837 case Token::EQ: // fall through
1838 case Token::PLUSEQ: // fall through
1839 case Token::MINUSEQ: // fall through
1840 case Token::STAREQ: // fall through
1841 case Token::SLASHEQ: // fall through
1842 case Token::PERCENTEQ: // fall through
1843 case Token::SHLEQ: // fall through
1844 case Token::SHREQ: // fall through
1845 case Token::BITWISEOREQ: // fall through
1846 case Token::BITWISEXOREQ: // fall through
1847 case Token::BITWISEANDEQ: // fall through
1848 case Token::LOGICALOREQ: // fall through
1849 case Token::LOGICALXOREQ: // fall through
1850 case Token::LOGICALANDEQ:
1851 return true;
1852 default:
1853 return false;
1854 }
1855}
1856
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001857SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001858 // handle cases where we don't necessarily evaluate both LHS and RHS
1859 switch (b.fOperator) {
1860 case Token::EQ: {
1861 SpvId rhs = this->writeExpression(*b.fRight, out);
1862 this->getLValue(*b.fLeft, out)->store(rhs, out);
1863 return rhs;
1864 }
1865 case Token::LOGICALAND:
1866 return this->writeLogicalAnd(b, out);
1867 case Token::LOGICALOR:
1868 return this->writeLogicalOr(b, out);
1869 default:
1870 break;
1871 }
1872
1873 // "normal" operators
ethannicholasd598f792016-07-25 10:08:54 -07001874 const Type& resultType = b.fType;
ethannicholasb3058bd2016-07-01 08:22:01 -07001875 std::unique_ptr<LValue> lvalue;
1876 SpvId lhs;
1877 if (is_assignment(b.fOperator)) {
1878 lvalue = this->getLValue(*b.fLeft, out);
1879 lhs = lvalue->load(out);
1880 } else {
1881 lvalue = nullptr;
1882 lhs = this->writeExpression(*b.fLeft, out);
1883 }
1884 SpvId rhs = this->writeExpression(*b.fRight, out);
1885 // component type we are operating on: float, int, uint
1886 const Type* operandType;
1887 // IR allows mismatched types in expressions (e.g. vec2 * float), but they need special handling
1888 // in SPIR-V
1889 if (b.fLeft->fType != b.fRight->fType) {
ethannicholasd598f792016-07-25 10:08:54 -07001890 if (b.fLeft->fType.kind() == Type::kVector_Kind &&
1891 b.fRight->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001892 // promote number to vector
1893 SpvId vec = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001894 this->writeOpCode(SpvOpCompositeConstruct, 3 + b.fType.columns(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001895 this->writeWord(this->getType(resultType), out);
1896 this->writeWord(vec, out);
1897 for (int i = 0; i < resultType.columns(); i++) {
1898 this->writeWord(rhs, out);
1899 }
1900 rhs = vec;
ethannicholasd598f792016-07-25 10:08:54 -07001901 operandType = &b.fRight->fType;
1902 } else if (b.fRight->fType.kind() == Type::kVector_Kind &&
1903 b.fLeft->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001904 // promote number to vector
1905 SpvId vec = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001906 this->writeOpCode(SpvOpCompositeConstruct, 3 + b.fType.columns(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001907 this->writeWord(this->getType(resultType), out);
1908 this->writeWord(vec, out);
1909 for (int i = 0; i < resultType.columns(); i++) {
1910 this->writeWord(lhs, out);
1911 }
1912 lhs = vec;
1913 ASSERT(!lvalue);
ethannicholasd598f792016-07-25 10:08:54 -07001914 operandType = &b.fLeft->fType;
1915 } else if (b.fLeft->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001916 SpvOp_ op;
ethannicholasd598f792016-07-25 10:08:54 -07001917 if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001918 op = SpvOpMatrixTimesMatrix;
ethannicholasd598f792016-07-25 10:08:54 -07001919 } else if (b.fRight->fType.kind() == Type::kVector_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001920 op = SpvOpMatrixTimesVector;
1921 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001922 ASSERT(b.fRight->fType.kind() == Type::kScalar_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001923 op = SpvOpMatrixTimesScalar;
1924 }
1925 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001926 this->writeInstruction(op, this->getType(b.fType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001927 if (b.fOperator == Token::STAREQ) {
1928 lvalue->store(result, out);
1929 } else {
1930 ASSERT(b.fOperator == Token::STAR);
1931 }
1932 return result;
ethannicholasd598f792016-07-25 10:08:54 -07001933 } else if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001934 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001935 if (b.fLeft->fType.kind() == Type::kVector_Kind) {
1936 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(b.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07001937 lhs, rhs, out);
1938 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001939 ASSERT(b.fLeft->fType.kind() == Type::kScalar_Kind);
1940 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(b.fType), result, rhs,
ethannicholasb3058bd2016-07-01 08:22:01 -07001941 lhs, out);
1942 }
1943 if (b.fOperator == Token::STAREQ) {
1944 lvalue->store(result, out);
1945 } else {
1946 ASSERT(b.fOperator == Token::STAR);
1947 }
1948 return result;
1949 } else {
1950 ABORT("unsupported binary expression: %s", b.description().c_str());
1951 }
1952 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001953 operandType = &b.fLeft->fType;
1954 ASSERT(*operandType == b.fRight->fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001955 }
1956 switch (b.fOperator) {
1957 case Token::EQEQ:
ethannicholasd598f792016-07-25 10:08:54 -07001958 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001959 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdEqual,
1960 SpvOpIEqual, SpvOpIEqual, SpvOpLogicalEqual, out);
1961 case Token::NEQ:
ethannicholasd598f792016-07-25 10:08:54 -07001962 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001963 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdNotEqual,
1964 SpvOpINotEqual, SpvOpINotEqual, SpvOpLogicalNotEqual,
1965 out);
1966 case Token::GT:
ethannicholasd598f792016-07-25 10:08:54 -07001967 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001968 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
1969 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
1970 SpvOpUGreaterThan, SpvOpUndef, out);
1971 case Token::LT:
ethannicholasd598f792016-07-25 10:08:54 -07001972 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001973 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
1974 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
1975 case Token::GTEQ:
ethannicholasd598f792016-07-25 10:08:54 -07001976 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001977 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
1978 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
1979 SpvOpUGreaterThanEqual, SpvOpUndef, out);
1980 case Token::LTEQ:
ethannicholasd598f792016-07-25 10:08:54 -07001981 ASSERT(resultType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001982 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
1983 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
1984 SpvOpULessThanEqual, SpvOpUndef, out);
1985 case Token::PLUS:
1986 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
1987 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
1988 case Token::MINUS:
1989 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
1990 SpvOpISub, SpvOpISub, SpvOpUndef, out);
1991 case Token::STAR:
ethannicholasd598f792016-07-25 10:08:54 -07001992 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
1993 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001994 // matrix multiply
1995 SpvId result = this->nextId();
1996 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
1997 lhs, rhs, out);
1998 return result;
1999 }
2000 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
2001 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2002 case Token::SLASH:
2003 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
2004 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
2005 case Token::PLUSEQ: {
2006 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
2007 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2008 ASSERT(lvalue);
2009 lvalue->store(result, out);
2010 return result;
2011 }
2012 case Token::MINUSEQ: {
2013 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
2014 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2015 ASSERT(lvalue);
2016 lvalue->store(result, out);
2017 return result;
2018 }
2019 case Token::STAREQ: {
ethannicholasd598f792016-07-25 10:08:54 -07002020 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
2021 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002022 // matrix multiply
2023 SpvId result = this->nextId();
2024 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2025 lhs, rhs, out);
2026 ASSERT(lvalue);
2027 lvalue->store(result, out);
2028 return result;
2029 }
2030 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
2031 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2032 ASSERT(lvalue);
2033 lvalue->store(result, out);
2034 return result;
2035 }
2036 case Token::SLASHEQ: {
2037 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
2038 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
2039 ASSERT(lvalue);
2040 lvalue->store(result, out);
2041 return result;
2042 }
2043 default:
2044 // FIXME: missing support for some operators (bitwise, &&=, ||=, shift...)
2045 ABORT("unsupported binary expression: %s", b.description().c_str());
2046 }
2047}
2048
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002049SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002050 ASSERT(a.fOperator == Token::LOGICALAND);
ethannicholasd598f792016-07-25 10:08:54 -07002051 BoolLiteral falseLiteral(fContext, Position(), false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002052 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2053 SpvId lhs = this->writeExpression(*a.fLeft, out);
2054 SpvId rhsLabel = this->nextId();
2055 SpvId end = this->nextId();
2056 SpvId lhsBlock = fCurrentBlock;
2057 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2058 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2059 this->writeLabel(rhsLabel, out);
2060 SpvId rhs = this->writeExpression(*a.fRight, out);
2061 SpvId rhsBlock = fCurrentBlock;
2062 this->writeInstruction(SpvOpBranch, end, out);
2063 this->writeLabel(end, out);
2064 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002065 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
2066 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002067 return result;
2068}
2069
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002070SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002071 ASSERT(o.fOperator == Token::LOGICALOR);
ethannicholasd598f792016-07-25 10:08:54 -07002072 BoolLiteral trueLiteral(fContext, Position(), true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002073 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2074 SpvId lhs = this->writeExpression(*o.fLeft, out);
2075 SpvId rhsLabel = this->nextId();
2076 SpvId end = this->nextId();
2077 SpvId lhsBlock = fCurrentBlock;
2078 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2079 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2080 this->writeLabel(rhsLabel, out);
2081 SpvId rhs = this->writeExpression(*o.fRight, out);
2082 SpvId rhsBlock = fCurrentBlock;
2083 this->writeInstruction(SpvOpBranch, end, out);
2084 this->writeLabel(end, out);
2085 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002086 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
2087 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002088 return result;
2089}
2090
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002091SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002092 SpvId test = this->writeExpression(*t.fTest, out);
2093 if (t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
2094 // both true and false are constants, can just use OpSelect
2095 SpvId result = this->nextId();
2096 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2097 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
ethannicholasd598f792016-07-25 10:08:54 -07002098 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002099 out);
2100 return result;
2101 }
2102 // was originally using OpPhi to choose the result, but for some reason that is crashing on
2103 // Adreno. Switched to storing the result in a temp variable as glslang does.
2104 SpvId var = this->nextId();
2105 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002106 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002107 SpvId trueLabel = this->nextId();
2108 SpvId falseLabel = this->nextId();
2109 SpvId end = this->nextId();
2110 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2111 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2112 this->writeLabel(trueLabel, out);
2113 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2114 this->writeInstruction(SpvOpBranch, end, out);
2115 this->writeLabel(falseLabel, out);
2116 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2117 this->writeInstruction(SpvOpBranch, end, out);
2118 this->writeLabel(end, out);
2119 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002120 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002121 return result;
2122}
2123
ethannicholasd598f792016-07-25 10:08:54 -07002124std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2125 if (type == *context.fInt_Type) {
2126 return std::unique_ptr<Expression>(new IntLiteral(context, Position(), 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07002127 }
ethannicholasd598f792016-07-25 10:08:54 -07002128 else if (type == *context.fFloat_Type) {
2129 return std::unique_ptr<Expression>(new FloatLiteral(context, Position(), 1.0));
ethannicholasb3058bd2016-07-01 08:22:01 -07002130 } else {
2131 ABORT("math is unsupported on type '%s'")
2132 }
2133}
2134
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002135SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002136 if (p.fOperator == Token::MINUS) {
2137 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002138 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002139 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002140 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002141 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002142 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002143 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2144 } else {
2145 ABORT("unsupported prefix expression %s", p.description().c_str());
2146 };
2147 return result;
2148 }
2149 switch (p.fOperator) {
2150 case Token::PLUS:
2151 return this->writeExpression(*p.fOperand, out);
2152 case Token::PLUSPLUS: {
2153 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002154 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
2155 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
ethannicholasb3058bd2016-07-01 08:22:01 -07002156 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
2157 out);
2158 lv->store(result, out);
2159 return result;
2160 }
2161 case Token::MINUSMINUS: {
2162 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002163 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
2164 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
ethannicholasb3058bd2016-07-01 08:22:01 -07002165 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
2166 out);
2167 lv->store(result, out);
2168 return result;
2169 }
ethannicholas5961bc92016-10-12 06:39:56 -07002170 case Token::LOGICALNOT: {
ethannicholasd598f792016-07-25 10:08:54 -07002171 ASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002172 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002173 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002174 this->writeExpression(*p.fOperand, out), out);
2175 return result;
2176 }
ethannicholas5961bc92016-10-12 06:39:56 -07002177 case Token::BITWISENOT: {
2178 SpvId result = this->nextId();
2179 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2180 this->writeExpression(*p.fOperand, out), out);
2181 return result;
2182 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002183 default:
2184 ABORT("unsupported prefix expression: %s", p.description().c_str());
2185 }
2186}
2187
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002188SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002189 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2190 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002191 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002192 switch (p.fOperator) {
2193 case Token::PLUSPLUS: {
ethannicholasd598f792016-07-25 10:08:54 -07002194 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002195 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2196 lv->store(temp, out);
2197 return result;
2198 }
2199 case Token::MINUSMINUS: {
ethannicholasd598f792016-07-25 10:08:54 -07002200 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002201 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2202 lv->store(temp, out);
2203 return result;
2204 }
2205 default:
2206 ABORT("unsupported postfix expression %s", p.description().c_str());
2207 }
2208}
2209
ethannicholasf789b382016-08-03 12:43:36 -07002210SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002211 if (b.fValue) {
2212 if (fBoolTrue == 0) {
2213 fBoolTrue = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002214 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002215 fConstantBuffer);
2216 }
2217 return fBoolTrue;
2218 } else {
2219 if (fBoolFalse == 0) {
2220 fBoolFalse = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002221 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002222 fConstantBuffer);
2223 }
2224 return fBoolFalse;
2225 }
2226}
2227
ethannicholasf789b382016-08-03 12:43:36 -07002228SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholasd598f792016-07-25 10:08:54 -07002229 if (i.fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002230 auto entry = fIntConstants.find(i.fValue);
2231 if (entry == fIntConstants.end()) {
2232 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002233 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002234 fConstantBuffer);
2235 fIntConstants[i.fValue] = result;
2236 return result;
2237 }
2238 return entry->second;
2239 } else {
ethannicholasd598f792016-07-25 10:08:54 -07002240 ASSERT(i.fType == *fContext.fUInt_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002241 auto entry = fUIntConstants.find(i.fValue);
2242 if (entry == fUIntConstants.end()) {
2243 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002244 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002245 fConstantBuffer);
2246 fUIntConstants[i.fValue] = result;
2247 return result;
2248 }
2249 return entry->second;
2250 }
2251}
2252
ethannicholasf789b382016-08-03 12:43:36 -07002253SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
ethannicholasd598f792016-07-25 10:08:54 -07002254 if (f.fType == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002255 float value = (float) f.fValue;
2256 auto entry = fFloatConstants.find(value);
2257 if (entry == fFloatConstants.end()) {
2258 SpvId result = this->nextId();
2259 uint32_t bits;
2260 ASSERT(sizeof(bits) == sizeof(value));
2261 memcpy(&bits, &value, sizeof(bits));
ethannicholasd598f792016-07-25 10:08:54 -07002262 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
ethannicholasb3058bd2016-07-01 08:22:01 -07002263 fConstantBuffer);
2264 fFloatConstants[value] = result;
2265 return result;
2266 }
2267 return entry->second;
2268 } else {
ethannicholasd598f792016-07-25 10:08:54 -07002269 ASSERT(f.fType == *fContext.fDouble_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002270 auto entry = fDoubleConstants.find(f.fValue);
2271 if (entry == fDoubleConstants.end()) {
2272 SpvId result = this->nextId();
2273 uint64_t bits;
2274 ASSERT(sizeof(bits) == sizeof(f.fValue));
2275 memcpy(&bits, &f.fValue, sizeof(bits));
ethannicholasd598f792016-07-25 10:08:54 -07002276 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002277 bits & 0xffffffff, bits >> 32, fConstantBuffer);
2278 fDoubleConstants[f.fValue] = result;
2279 return result;
2280 }
2281 return entry->second;
2282 }
2283}
2284
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002285SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, SkWStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002286 SpvId result = fFunctionMap[&f];
2287 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002288 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
ethannicholasd598f792016-07-25 10:08:54 -07002289 this->writeInstruction(SpvOpName, result, f.fName.c_str(), fNameBuffer);
2290 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002291 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002292 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002293 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002294 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002295 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2296 }
2297 return result;
2298}
2299
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002300SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002301 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2302 this->writeLabel(this->nextId(), out);
ethannicholasd598f792016-07-25 10:08:54 -07002303 if (f.fDeclaration.fName == "main") {
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002304 write_data(*fGlobalInitializersBuffer.detachAsData(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002305 }
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002306 SkDynamicMemoryWStream bodyBuffer;
ethannicholasb3058bd2016-07-01 08:22:01 -07002307 this->writeBlock(*f.fBody, bodyBuffer);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002308 write_data(*fVariableBuffer.detachAsData(), out);
2309 write_data(*bodyBuffer.detachAsData(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002310 if (fCurrentBlock) {
2311 this->writeInstruction(SpvOpReturn, out);
2312 }
2313 this->writeInstruction(SpvOpFunctionEnd, out);
2314 return result;
2315}
2316
2317void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2318 if (layout.fLocation >= 0) {
2319 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
2320 fDecorationBuffer);
2321 }
2322 if (layout.fBinding >= 0) {
2323 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
2324 fDecorationBuffer);
2325 }
2326 if (layout.fIndex >= 0) {
2327 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
2328 fDecorationBuffer);
2329 }
2330 if (layout.fSet >= 0) {
2331 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
2332 fDecorationBuffer);
2333 }
ethannicholas5961bc92016-10-12 06:39:56 -07002334 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002335 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
2336 fDecorationBuffer);
2337 }
2338}
2339
2340void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2341 if (layout.fLocation >= 0) {
2342 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
2343 layout.fLocation, fDecorationBuffer);
2344 }
2345 if (layout.fBinding >= 0) {
2346 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
2347 layout.fBinding, fDecorationBuffer);
2348 }
2349 if (layout.fIndex >= 0) {
2350 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
2351 layout.fIndex, fDecorationBuffer);
2352 }
2353 if (layout.fSet >= 0) {
2354 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
2355 layout.fSet, fDecorationBuffer);
2356 }
2357 if (layout.fBuiltin >= 0) {
2358 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
2359 layout.fBuiltin, fDecorationBuffer);
2360 }
2361}
2362
ethannicholasf789b382016-08-03 12:43:36 -07002363SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
egdaniel988283c2016-11-16 07:29:51 -08002364 SpvId type = this->getType(intf.fVariable.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002365 SpvId result = this->nextId();
2366 this->writeInstruction(SpvOpDecorate, type, SpvDecorationBlock, fDecorationBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002367 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002368 SpvId ptrType = this->nextId();
2369 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, type, fConstantBuffer);
2370 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002371 this->writeLayout(intf.fVariable.fModifiers.fLayout, result);
2372 fVariableMap[&intf.fVariable] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002373 return result;
2374}
2375
ethannicholas5961bc92016-10-12 06:39:56 -07002376#define BUILTIN_IGNORE 9999
2377void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002378 SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002379 for (size_t i = 0; i < decl.fVars.size(); i++) {
ethannicholas14fe8cc2016-09-07 13:37:16 -07002380 const VarDeclaration& varDecl = decl.fVars[i];
2381 const Variable* var = varDecl.fVar;
ethannicholas5961bc92016-10-12 06:39:56 -07002382 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2383 continue;
2384 }
2385 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2386 kind != Program::kFragment_Kind) {
2387 continue;
2388 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002389 if (!var->fIsReadFrom && !var->fIsWrittenTo &&
2390 !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
2391 Modifiers::kOut_Flag |
2392 Modifiers::kUniform_Flag))) {
ethannicholasd598f792016-07-25 10:08:54 -07002393 // variable is dead and not an input / output var (the Vulkan debug layers complain if
2394 // we elide an interface var, even if it's dead)
ethannicholasb3058bd2016-07-01 08:22:01 -07002395 continue;
2396 }
2397 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002398 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002399 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002400 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002401 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002402 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
2403 if (var->fType.kind() == Type::kSampler_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002404 storageClass = SpvStorageClassUniformConstant;
2405 } else {
2406 storageClass = SpvStorageClassUniform;
2407 }
2408 } else {
2409 storageClass = SpvStorageClassPrivate;
2410 }
2411 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002412 fVariableMap[var] = id;
2413 SpvId type = this->getPointerType(var->fType, storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -07002414 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
ethannicholas14fe8cc2016-09-07 13:37:16 -07002415 this->writeInstruction(SpvOpName, id, var->fName.c_str(), fNameBuffer);
2416 if (var->fType.kind() == Type::kMatrix_Kind) {
egdaniel988283c2016-11-16 07:29:51 -08002417 this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -07002418 fDecorationBuffer);
egdaniel988283c2016-11-16 07:29:51 -08002419 this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationMatrixStride,
2420 (SpvId) var->fType.stride(), fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002421 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002422 if (varDecl.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -07002423 ASSERT(!fCurrentBlock);
2424 fCurrentBlock = -1;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002425 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002426 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002427 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002428 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002429 this->writeLayout(var->fModifiers.fLayout, id);
ethannicholasb3058bd2016-07-01 08:22:01 -07002430 }
2431}
2432
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002433void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, SkWStream& out) {
ethannicholas14fe8cc2016-09-07 13:37:16 -07002434 for (const auto& varDecl : decl.fVars) {
2435 const Variable* var = varDecl.fVar;
ethannicholasb3058bd2016-07-01 08:22:01 -07002436 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002437 fVariableMap[var] = id;
2438 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002439 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
ethannicholas14fe8cc2016-09-07 13:37:16 -07002440 this->writeInstruction(SpvOpName, id, var->fName.c_str(), fNameBuffer);
2441 if (varDecl.fValue) {
2442 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002443 this->writeInstruction(SpvOpStore, id, value, out);
2444 }
2445 }
2446}
2447
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002448void SPIRVCodeGenerator::writeStatement(const Statement& s, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002449 switch (s.fKind) {
2450 case Statement::kBlock_Kind:
2451 this->writeBlock((Block&) s, out);
2452 break;
2453 case Statement::kExpression_Kind:
2454 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2455 break;
2456 case Statement::kReturn_Kind:
2457 this->writeReturnStatement((ReturnStatement&) s, out);
2458 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002459 case Statement::kVarDeclarations_Kind:
2460 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002461 break;
2462 case Statement::kIf_Kind:
2463 this->writeIfStatement((IfStatement&) s, out);
2464 break;
2465 case Statement::kFor_Kind:
2466 this->writeForStatement((ForStatement&) s, out);
2467 break;
2468 case Statement::kBreak_Kind:
2469 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2470 break;
2471 case Statement::kContinue_Kind:
2472 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2473 break;
2474 case Statement::kDiscard_Kind:
2475 this->writeInstruction(SpvOpKill, out);
2476 break;
2477 default:
2478 ABORT("unsupported statement: %s", s.description().c_str());
2479 }
2480}
2481
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002482void SPIRVCodeGenerator::writeBlock(const Block& b, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002483 for (size_t i = 0; i < b.fStatements.size(); i++) {
2484 this->writeStatement(*b.fStatements[i], out);
2485 }
2486}
2487
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002488void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002489 SpvId test = this->writeExpression(*stmt.fTest, out);
2490 SpvId ifTrue = this->nextId();
2491 SpvId ifFalse = this->nextId();
2492 if (stmt.fIfFalse) {
2493 SpvId end = this->nextId();
2494 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2495 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2496 this->writeLabel(ifTrue, out);
2497 this->writeStatement(*stmt.fIfTrue, out);
2498 if (fCurrentBlock) {
2499 this->writeInstruction(SpvOpBranch, end, out);
2500 }
2501 this->writeLabel(ifFalse, out);
2502 this->writeStatement(*stmt.fIfFalse, out);
2503 if (fCurrentBlock) {
2504 this->writeInstruction(SpvOpBranch, end, out);
2505 }
2506 this->writeLabel(end, out);
2507 } else {
2508 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2509 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2510 this->writeLabel(ifTrue, out);
2511 this->writeStatement(*stmt.fIfTrue, out);
2512 if (fCurrentBlock) {
2513 this->writeInstruction(SpvOpBranch, ifFalse, out);
2514 }
2515 this->writeLabel(ifFalse, out);
2516 }
2517}
2518
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002519void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002520 if (f.fInitializer) {
2521 this->writeStatement(*f.fInitializer, out);
2522 }
2523 SpvId header = this->nextId();
2524 SpvId start = this->nextId();
2525 SpvId body = this->nextId();
2526 SpvId next = this->nextId();
2527 fContinueTarget.push(next);
2528 SpvId end = this->nextId();
2529 fBreakTarget.push(end);
2530 this->writeInstruction(SpvOpBranch, header, out);
2531 this->writeLabel(header, out);
2532 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002533 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002534 this->writeLabel(start, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002535 if (f.fTest) {
2536 SpvId test = this->writeExpression(*f.fTest, out);
2537 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2538 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002539 this->writeLabel(body, out);
2540 this->writeStatement(*f.fStatement, out);
2541 if (fCurrentBlock) {
2542 this->writeInstruction(SpvOpBranch, next, out);
2543 }
2544 this->writeLabel(next, out);
2545 if (f.fNext) {
2546 this->writeExpression(*f.fNext, out);
2547 }
2548 this->writeInstruction(SpvOpBranch, header, out);
2549 this->writeLabel(end, out);
2550 fBreakTarget.pop();
2551 fContinueTarget.pop();
2552}
2553
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002554void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002555 if (r.fExpression) {
2556 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
2557 out);
2558 } else {
2559 this->writeInstruction(SpvOpReturn, out);
2560 }
2561}
2562
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002563void SPIRVCodeGenerator::writeInstructions(const Program& program, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002564 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002565 SkDynamicMemoryWStream body;
ethannicholasb3058bd2016-07-01 08:22:01 -07002566 std::vector<SpvId> interfaceVars;
2567 // assign IDs to functions
2568 for (size_t i = 0; i < program.fElements.size(); i++) {
2569 if (program.fElements[i]->fKind == ProgramElement::kFunction_Kind) {
2570 FunctionDefinition& f = (FunctionDefinition&) *program.fElements[i];
ethannicholasd598f792016-07-25 10:08:54 -07002571 fFunctionMap[&f.fDeclaration] = this->nextId();
ethannicholasb3058bd2016-07-01 08:22:01 -07002572 }
2573 }
2574 for (size_t i = 0; i < program.fElements.size(); i++) {
2575 if (program.fElements[i]->fKind == ProgramElement::kInterfaceBlock_Kind) {
2576 InterfaceBlock& intf = (InterfaceBlock&) *program.fElements[i];
2577 SpvId id = this->writeInterfaceBlock(intf);
ethannicholasd598f792016-07-25 10:08:54 -07002578 if ((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
2579 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002580 interfaceVars.push_back(id);
2581 }
2582 }
2583 }
2584 for (size_t i = 0; i < program.fElements.size(); i++) {
2585 if (program.fElements[i]->fKind == ProgramElement::kVar_Kind) {
ethannicholas5961bc92016-10-12 06:39:56 -07002586 this->writeGlobalVars(program.fKind, ((VarDeclarations&) *program.fElements[i]),
2587 body);
ethannicholasb3058bd2016-07-01 08:22:01 -07002588 }
2589 }
2590 for (size_t i = 0; i < program.fElements.size(); i++) {
2591 if (program.fElements[i]->fKind == ProgramElement::kFunction_Kind) {
2592 this->writeFunction(((FunctionDefinition&) *program.fElements[i]), body);
2593 }
2594 }
ethannicholasd598f792016-07-25 10:08:54 -07002595 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07002596 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07002597 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07002598 main = entry.first;
2599 }
2600 }
2601 ASSERT(main);
2602 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07002603 const Variable* var = entry.first;
ethannicholasb3058bd2016-07-01 08:22:01 -07002604 if (var->fStorage == Variable::kGlobal_Storage &&
2605 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
2606 (var->fModifiers.fFlags & Modifiers::kOut_Flag))) {
2607 interfaceVars.push_back(entry.second);
2608 }
2609 }
2610 this->writeCapabilities(out);
2611 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
2612 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
2613 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (strlen(main->fName.c_str()) + 4) / 4) +
2614 (int32_t) interfaceVars.size(), out);
2615 switch (program.fKind) {
2616 case Program::kVertex_Kind:
2617 this->writeWord(SpvExecutionModelVertex, out);
2618 break;
2619 case Program::kFragment_Kind:
2620 this->writeWord(SpvExecutionModelFragment, out);
2621 break;
2622 }
2623 this->writeWord(fFunctionMap[main], out);
2624 this->writeString(main->fName.c_str(), out);
2625 for (int var : interfaceVars) {
2626 this->writeWord(var, out);
2627 }
2628 if (program.fKind == Program::kFragment_Kind) {
2629 this->writeInstruction(SpvOpExecutionMode,
2630 fFunctionMap[main],
2631 SpvExecutionModeOriginUpperLeft,
2632 out);
2633 }
2634 for (size_t i = 0; i < program.fElements.size(); i++) {
2635 if (program.fElements[i]->fKind == ProgramElement::kExtension_Kind) {
2636 this->writeInstruction(SpvOpSourceExtension,
2637 ((Extension&) *program.fElements[i]).fName.c_str(),
2638 out);
2639 }
2640 }
2641
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002642 write_data(*fNameBuffer.detachAsData(), out);
2643 write_data(*fDecorationBuffer.detachAsData(), out);
2644 write_data(*fConstantBuffer.detachAsData(), out);
2645 write_data(*fExternalFunctionsBuffer.detachAsData(), out);
2646 write_data(*body.detachAsData(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002647}
2648
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002649void SPIRVCodeGenerator::generateCode(const Program& program, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002650 this->writeWord(SpvMagicNumber, out);
2651 this->writeWord(SpvVersion, out);
2652 this->writeWord(SKSL_MAGIC, out);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002653 SkDynamicMemoryWStream buffer;
ethannicholasb3058bd2016-07-01 08:22:01 -07002654 this->writeInstructions(program, buffer);
2655 this->writeWord(fIdCount, out);
2656 this->writeWord(0, out); // reserved, always zero
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002657 write_data(*buffer.detachAsData(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002658}
2659
2660}