blob: 8afd13688c59f56248b609b25920f30c1056b56b [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);
ethannicholasb3058bd2016-07-01 08:22:01 -0700106
Greg Daniel64773e62016-11-22 09:44:03 -0500107 fIntrinsicMap[SkString("subpassLoad")] = SPECIAL(SubpassLoad);
108
109 fIntrinsicMap[SkString("any")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500110 SpvOpUndef, SpvOpUndef, SpvOpAny);
Greg Daniel64773e62016-11-22 09:44:03 -0500111 fIntrinsicMap[SkString("all")] = std::make_tuple(kSPIRV_IntrinsicKind, SpvOpUndef,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500112 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,
Greg Daniel64773e62016-11-22 09:44:03 -0500124 SpvOpSLessThanEqual,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500125 SpvOpULessThanEqual,
126 SpvOpFOrdLessThanEqual,
127 SpvOpUndef);
128 fIntrinsicMap[SkString("greaterThan")] = std::make_tuple(kSPIRV_IntrinsicKind,
Greg Daniel64773e62016-11-22 09:44:03 -0500129 SpvOpSGreaterThan,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500130 SpvOpUGreaterThan,
Greg Daniel64773e62016-11-22 09:44:03 -0500131 SpvOpFOrdGreaterThan,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500132 SpvOpUndef);
Greg Daniel64773e62016-11-22 09:44:03 -0500133 fIntrinsicMap[SkString("greaterThanEqual")] = std::make_tuple(kSPIRV_IntrinsicKind,
134 SpvOpSGreaterThanEqual,
135 SpvOpUGreaterThanEqual,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -0500136 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
Greg Daniel64773e62016-11-22 09:44:03 -0500872void 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
Greg Daniel64773e62016-11-22 09:44:03 -0500880void 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
Greg Daniel64773e62016-11-22 09:44:03 -0500889void 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
Greg Daniel64773e62016-11-22 09:44:03 -0500896void 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
Greg Daniel64773e62016-11-22 09:44:03 -0500904void 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
Greg Daniel64773e62016-11-22 09:44:03 -0500913void 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
Greg Daniel64773e62016-11-22 09:44:03 -0500924void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700925 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
Greg Daniel64773e62016-11-22 09:44:03 -0500936void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700937 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
Greg Daniel64773e62016-11-22 09:44:03 -0500949void SPIRVCodeGenerator::writeInstruction(SpvOp_ opCode, int32_t word1, int32_t word2,
ethannicholasb3058bd2016-07-01 08:22:01 -0700950 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
Ethan Nicholas19671772016-11-28 16:30:17 -0500976void SPIRVCodeGenerator::writeStruct(const Type& type, const MemoryLayout& memoryLayout,
977 SpvId resultId) {
ethannicholasb3058bd2016-07-01 08:22:01 -0700978 this->writeInstruction(SpvOpName, resultId, type.name().c_str(), fNameBuffer);
979 // go ahead and write all of the field types, so we don't inadvertently write them while we're
980 // in the middle of writing the struct instruction
981 std::vector<SpvId> types;
982 for (const auto& f : type.fields()) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500983 types.push_back(this->getType(*f.fType, memoryLayout));
ethannicholasb3058bd2016-07-01 08:22:01 -0700984 }
985 this->writeOpCode(SpvOpTypeStruct, 2 + (int32_t) types.size(), fConstantBuffer);
986 this->writeWord(resultId, fConstantBuffer);
987 for (SpvId id : types) {
988 this->writeWord(id, fConstantBuffer);
989 }
990 size_t offset = 0;
991 for (int32_t i = 0; i < (int32_t) type.fields().size(); i++) {
Ethan Nicholas19671772016-11-28 16:30:17 -0500992 size_t size = memoryLayout.size(*type.fields()[i].fType);
993 size_t alignment = memoryLayout.alignment(*type.fields()[i].fType);
994 const Layout& fieldLayout = type.fields()[i].fModifiers.fLayout;
995 if (fieldLayout.fOffset >= 0) {
996 if (fieldLayout.fOffset <= (int) offset) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -0500997 fErrors.error(type.fPosition,
998 "offset of field '" + type.fields()[i].fName + "' must be at "
999 "least " + to_string((int) offset));
Ethan Nicholas19671772016-11-28 16:30:17 -05001000 }
1001 if (fieldLayout.fOffset % alignment) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001002 fErrors.error(type.fPosition,
1003 "offset of field '" + type.fields()[i].fName + "' must be a multiple"
1004 " of " + to_string((int) alignment));
Ethan Nicholas19671772016-11-28 16:30:17 -05001005 }
1006 offset = fieldLayout.fOffset;
1007 } else {
1008 size_t mod = offset % alignment;
1009 if (mod) {
1010 offset += alignment - mod;
1011 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001012 }
1013 this->writeInstruction(SpvOpMemberName, resultId, i, type.fields()[i].fName.c_str(),
1014 fNameBuffer);
Ethan Nicholas19671772016-11-28 16:30:17 -05001015 this->writeLayout(fieldLayout, resultId, i);
ethannicholasb3058bd2016-07-01 08:22:01 -07001016 if (type.fields()[i].fModifiers.fLayout.fBuiltin < 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05001017 this->writeInstruction(SpvOpMemberDecorate, resultId, (SpvId) i, SpvDecorationOffset,
ethannicholasb3058bd2016-07-01 08:22:01 -07001018 (SpvId) offset, fDecorationBuffer);
1019 }
ethannicholas0730be72016-09-01 07:59:02 -07001020 if (type.fields()[i].fType->kind() == Type::kMatrix_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05001021 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -07001022 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -05001023 this->writeInstruction(SpvOpMemberDecorate, resultId, i, SpvDecorationMatrixStride,
Ethan Nicholas19671772016-11-28 16:30:17 -05001024 (SpvId) memoryLayout.stride(*type.fields()[i].fType),
ethannicholas8ac838d2016-11-22 08:39:36 -08001025 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001026 }
1027 offset += size;
ethannicholas0730be72016-09-01 07:59:02 -07001028 Type::Kind kind = type.fields()[i].fType->kind();
ethannicholasb3058bd2016-07-01 08:22:01 -07001029 if ((kind == Type::kArray_Kind || kind == Type::kStruct_Kind) && offset % alignment != 0) {
1030 offset += alignment - offset % alignment;
1031 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001032 }
1033}
1034
1035SpvId SPIRVCodeGenerator::getType(const Type& type) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001036 return this->getType(type, fDefaultLayout);
1037}
1038
1039SpvId SPIRVCodeGenerator::getType(const Type& type, const MemoryLayout& layout) {
1040 SkString key = type.name() + to_string((int) layout.fStd);
1041 auto entry = fTypeMap.find(key);
ethannicholasb3058bd2016-07-01 08:22:01 -07001042 if (entry == fTypeMap.end()) {
1043 SpvId result = this->nextId();
1044 switch (type.kind()) {
1045 case Type::kScalar_Kind:
ethannicholasd598f792016-07-25 10:08:54 -07001046 if (type == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001047 this->writeInstruction(SpvOpTypeBool, result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001048 } else if (type == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001049 this->writeInstruction(SpvOpTypeInt, result, 32, 1, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001050 } else if (type == *fContext.fUInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001051 this->writeInstruction(SpvOpTypeInt, result, 32, 0, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001052 } else if (type == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001053 this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001054 } else if (type == *fContext.fDouble_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001055 this->writeInstruction(SpvOpTypeFloat, result, 64, fConstantBuffer);
1056 } else {
1057 ASSERT(false);
1058 }
1059 break;
1060 case Type::kVector_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -05001061 this->writeInstruction(SpvOpTypeVector, result,
ethannicholas8ac838d2016-11-22 08:39:36 -08001062 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -07001063 type.columns(), fConstantBuffer);
1064 break;
1065 case Type::kMatrix_Kind:
Greg Daniel64773e62016-11-22 09:44:03 -05001066 this->writeInstruction(SpvOpTypeMatrix, result,
ethannicholas8ac838d2016-11-22 08:39:36 -08001067 this->getType(index_type(fContext, type), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -07001068 type.columns(), fConstantBuffer);
1069 break;
1070 case Type::kStruct_Kind:
ethannicholas8ac838d2016-11-22 08:39:36 -08001071 this->writeStruct(type, layout, result);
ethannicholasb3058bd2016-07-01 08:22:01 -07001072 break;
1073 case Type::kArray_Kind: {
1074 if (type.columns() > 0) {
ethannicholasd598f792016-07-25 10:08:54 -07001075 IntLiteral count(fContext, Position(), type.columns());
Greg Daniel64773e62016-11-22 09:44:03 -05001076 this->writeInstruction(SpvOpTypeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -08001077 this->getType(type.componentType(), layout),
ethannicholasb3058bd2016-07-01 08:22:01 -07001078 this->writeIntLiteral(count), fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -05001079 this->writeInstruction(SpvOpDecorate, result, SpvDecorationArrayStride,
ethannicholas8ac838d2016-11-22 08:39:36 -08001080 (int32_t) layout.stride(type),
1081 fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001082 } else {
1083 ABORT("runtime-sized arrays are not yet supported");
Greg Daniel64773e62016-11-22 09:44:03 -05001084 this->writeInstruction(SpvOpTypeRuntimeArray, result,
ethannicholas8ac838d2016-11-22 08:39:36 -08001085 this->getType(type.componentType(), layout),
1086 fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001087 }
1088 break;
1089 }
1090 case Type::kSampler_Kind: {
Greg Daniel64773e62016-11-22 09:44:03 -05001091 SpvId image = result;
1092 if (SpvDimSubpassData != type.dimensions()) {
1093 image = this->nextId();
1094 }
ethannicholas8ac838d2016-11-22 08:39:36 -08001095 this->writeInstruction(SpvOpTypeImage, image,
1096 this->getType(*fContext.fFloat_Type, layout),
ethannicholasb3058bd2016-07-01 08:22:01 -07001097 type.dimensions(), type.isDepth(), type.isArrayed(),
Greg Daniel64773e62016-11-22 09:44:03 -05001098 type.isMultisampled(), type.isSampled() ? 1 : 2,
ethannicholasb3058bd2016-07-01 08:22:01 -07001099 SpvImageFormatUnknown, fConstantBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -05001100 if (SpvDimSubpassData != type.dimensions()) {
1101 this->writeInstruction(SpvOpTypeSampledImage, result, image, fConstantBuffer);
1102 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001103 break;
1104 }
1105 default:
ethannicholasd598f792016-07-25 10:08:54 -07001106 if (type == *fContext.fVoid_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001107 this->writeInstruction(SpvOpTypeVoid, result, fConstantBuffer);
1108 } else {
1109 ABORT("invalid type: %s", type.description().c_str());
1110 }
1111 }
ethannicholas8ac838d2016-11-22 08:39:36 -08001112 fTypeMap[key] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001113 return result;
1114 }
1115 return entry->second;
1116}
1117
ethannicholasd598f792016-07-25 10:08:54 -07001118SpvId SPIRVCodeGenerator::getFunctionType(const FunctionDeclaration& function) {
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001119 SkString key = function.fReturnType.description() + "(";
1120 SkString separator;
ethannicholasd598f792016-07-25 10:08:54 -07001121 for (size_t i = 0; i < function.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001122 key += separator;
1123 separator = ", ";
ethannicholasd598f792016-07-25 10:08:54 -07001124 key += function.fParameters[i]->fType.description();
ethannicholasb3058bd2016-07-01 08:22:01 -07001125 }
1126 key += ")";
1127 auto entry = fTypeMap.find(key);
1128 if (entry == fTypeMap.end()) {
1129 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001130 int32_t length = 3 + (int32_t) function.fParameters.size();
1131 SpvId returnType = this->getType(function.fReturnType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001132 std::vector<SpvId> parameterTypes;
ethannicholasd598f792016-07-25 10:08:54 -07001133 for (size_t i = 0; i < function.fParameters.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001134 // glslang seems to treat all function arguments as pointers whether they need to be or
1135 // not. I was initially puzzled by this until I ran bizarre failures with certain
1136 // patterns of function calls and control constructs, as exemplified by this minimal
ethannicholasb3058bd2016-07-01 08:22:01 -07001137 // failure case:
1138 //
1139 // void sphere(float x) {
1140 // }
Greg Daniel64773e62016-11-22 09:44:03 -05001141 //
ethannicholasb3058bd2016-07-01 08:22:01 -07001142 // void map() {
1143 // sphere(1.0);
1144 // }
Greg Daniel64773e62016-11-22 09:44:03 -05001145 //
ethannicholasb3058bd2016-07-01 08:22:01 -07001146 // void main() {
1147 // for (int i = 0; i < 1; i++) {
1148 // map();
1149 // }
1150 // }
1151 //
Greg Daniel64773e62016-11-22 09:44:03 -05001152 // As of this writing, compiling this in the "obvious" way (with sphere taking a float)
1153 // crashes. Making it take a float* and storing the argument in a temporary variable,
ethannicholasb3058bd2016-07-01 08:22:01 -07001154 // as glslang does, fixes it. It's entirely possible I simply missed whichever part of
1155 // the spec makes this make sense.
1156// if (is_out(function->fParameters[i])) {
ethannicholasd598f792016-07-25 10:08:54 -07001157 parameterTypes.push_back(this->getPointerType(function.fParameters[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -07001158 SpvStorageClassFunction));
1159// } else {
ethannicholasd598f792016-07-25 10:08:54 -07001160// parameterTypes.push_back(this->getType(function.fParameters[i]->fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07001161// }
1162 }
1163 this->writeOpCode(SpvOpTypeFunction, length, fConstantBuffer);
1164 this->writeWord(result, fConstantBuffer);
1165 this->writeWord(returnType, fConstantBuffer);
1166 for (SpvId id : parameterTypes) {
1167 this->writeWord(id, fConstantBuffer);
1168 }
1169 fTypeMap[key] = result;
1170 return result;
1171 }
1172 return entry->second;
1173}
1174
ethannicholas8ac838d2016-11-22 08:39:36 -08001175SpvId SPIRVCodeGenerator::getPointerType(const Type& type, SpvStorageClass_ storageClass) {
1176 return this->getPointerType(type, fDefaultLayout, storageClass);
1177}
1178
1179SpvId SPIRVCodeGenerator::getPointerType(const Type& type, const MemoryLayout& layout,
ethannicholasb3058bd2016-07-01 08:22:01 -07001180 SpvStorageClass_ storageClass) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001181 SkString key = type.description() + "*" + to_string(layout.fStd) + to_string(storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -07001182 auto entry = fTypeMap.find(key);
1183 if (entry == fTypeMap.end()) {
1184 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05001185 this->writeInstruction(SpvOpTypePointer, result, storageClass,
ethannicholasd598f792016-07-25 10:08:54 -07001186 this->getType(type), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001187 fTypeMap[key] = result;
1188 return result;
1189 }
1190 return entry->second;
1191}
1192
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001193SpvId SPIRVCodeGenerator::writeExpression(const Expression& expr, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001194 switch (expr.fKind) {
1195 case Expression::kBinary_Kind:
1196 return this->writeBinaryExpression((BinaryExpression&) expr, out);
1197 case Expression::kBoolLiteral_Kind:
1198 return this->writeBoolLiteral((BoolLiteral&) expr);
1199 case Expression::kConstructor_Kind:
1200 return this->writeConstructor((Constructor&) expr, out);
1201 case Expression::kIntLiteral_Kind:
1202 return this->writeIntLiteral((IntLiteral&) expr);
1203 case Expression::kFieldAccess_Kind:
1204 return this->writeFieldAccess(((FieldAccess&) expr), out);
1205 case Expression::kFloatLiteral_Kind:
1206 return this->writeFloatLiteral(((FloatLiteral&) expr));
1207 case Expression::kFunctionCall_Kind:
1208 return this->writeFunctionCall((FunctionCall&) expr, out);
1209 case Expression::kPrefix_Kind:
1210 return this->writePrefixExpression((PrefixExpression&) expr, out);
1211 case Expression::kPostfix_Kind:
1212 return this->writePostfixExpression((PostfixExpression&) expr, out);
1213 case Expression::kSwizzle_Kind:
1214 return this->writeSwizzle((Swizzle&) expr, out);
1215 case Expression::kVariableReference_Kind:
1216 return this->writeVariableReference((VariableReference&) expr, out);
1217 case Expression::kTernary_Kind:
1218 return this->writeTernaryExpression((TernaryExpression&) expr, out);
1219 case Expression::kIndex_Kind:
1220 return this->writeIndexExpression((IndexExpression&) expr, out);
1221 default:
1222 ABORT("unsupported expression: %s", expr.description().c_str());
1223 }
1224 return -1;
1225}
1226
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001227SpvId SPIRVCodeGenerator::writeIntrinsicCall(const FunctionCall& c, SkWStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001228 auto intrinsic = fIntrinsicMap.find(c.fFunction.fName);
ethannicholasb3058bd2016-07-01 08:22:01 -07001229 ASSERT(intrinsic != fIntrinsicMap.end());
ethannicholasd598f792016-07-25 10:08:54 -07001230 const Type& type = c.fArguments[0]->fType;
ethannicholasb3058bd2016-07-01 08:22:01 -07001231 int32_t intrinsicId;
ethannicholasd598f792016-07-25 10:08:54 -07001232 if (std::get<0>(intrinsic->second) == kSpecial_IntrinsicKind || is_float(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001233 intrinsicId = std::get<1>(intrinsic->second);
ethannicholasd598f792016-07-25 10:08:54 -07001234 } else if (is_signed(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001235 intrinsicId = std::get<2>(intrinsic->second);
ethannicholasd598f792016-07-25 10:08:54 -07001236 } else if (is_unsigned(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001237 intrinsicId = std::get<3>(intrinsic->second);
ethannicholasd598f792016-07-25 10:08:54 -07001238 } else if (is_bool(fContext, type)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001239 intrinsicId = std::get<4>(intrinsic->second);
1240 } else {
1241 ABORT("invalid call %s, cannot operate on '%s'", c.description().c_str(),
ethannicholasd598f792016-07-25 10:08:54 -07001242 type.description().c_str());
ethannicholasb3058bd2016-07-01 08:22:01 -07001243 }
1244 switch (std::get<0>(intrinsic->second)) {
1245 case kGLSL_STD_450_IntrinsicKind: {
1246 SpvId result = this->nextId();
1247 std::vector<SpvId> arguments;
1248 for (size_t i = 0; i < c.fArguments.size(); i++) {
1249 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1250 }
1251 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001252 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001253 this->writeWord(result, out);
1254 this->writeWord(fGLSLExtendedInstructions, out);
1255 this->writeWord(intrinsicId, out);
1256 for (SpvId id : arguments) {
1257 this->writeWord(id, out);
1258 }
1259 return result;
1260 }
1261 case kSPIRV_IntrinsicKind: {
1262 SpvId result = this->nextId();
1263 std::vector<SpvId> arguments;
1264 for (size_t i = 0; i < c.fArguments.size(); i++) {
1265 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1266 }
1267 this->writeOpCode((SpvOp_) intrinsicId, 3 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001268 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001269 this->writeWord(result, out);
1270 for (SpvId id : arguments) {
1271 this->writeWord(id, out);
1272 }
1273 return result;
1274 }
1275 case kSpecial_IntrinsicKind:
1276 return this->writeSpecialIntrinsic(c, (SpecialIntrinsic) intrinsicId, out);
1277 default:
1278 ABORT("unsupported intrinsic kind");
1279 }
1280}
1281
Greg Daniel64773e62016-11-22 09:44:03 -05001282SpvId SPIRVCodeGenerator::writeSpecialIntrinsic(const FunctionCall& c, SpecialIntrinsic kind,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001283 SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001284 SpvId result = this->nextId();
1285 switch (kind) {
1286 case kAtan_SpecialIntrinsic: {
1287 std::vector<SpvId> arguments;
1288 for (size_t i = 0; i < c.fArguments.size(); i++) {
1289 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1290 }
1291 this->writeOpCode(SpvOpExtInst, 5 + (int32_t) arguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001292 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001293 this->writeWord(result, out);
1294 this->writeWord(fGLSLExtendedInstructions, out);
1295 this->writeWord(arguments.size() == 2 ? GLSLstd450Atan2 : GLSLstd450Atan, out);
1296 for (SpvId id : arguments) {
1297 this->writeWord(id, out);
1298 }
Greg Daniel64773e62016-11-22 09:44:03 -05001299 return result;
ethannicholasb3058bd2016-07-01 08:22:01 -07001300 }
1301 case kTexture_SpecialIntrinsic: {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -05001302 SpvOp_ op = SpvOpImageSampleImplicitLod;
1303 switch (c.fArguments[0]->fType.dimensions()) {
1304 case SpvDim1D:
1305 if (c.fArguments[1]->fType == *fContext.fVec2_Type) {
1306 op = SpvOpImageSampleProjImplicitLod;
1307 } else {
1308 ASSERT(c.fArguments[1]->fType == *fContext.fFloat_Type);
1309 }
1310 break;
1311 case SpvDim2D:
1312 if (c.fArguments[1]->fType == *fContext.fVec3_Type) {
1313 op = SpvOpImageSampleProjImplicitLod;
1314 } else {
1315 ASSERT(c.fArguments[1]->fType == *fContext.fVec2_Type);
1316 }
1317 break;
1318 case SpvDim3D:
1319 if (c.fArguments[1]->fType == *fContext.fVec4_Type) {
1320 op = SpvOpImageSampleProjImplicitLod;
1321 } else {
1322 ASSERT(c.fArguments[1]->fType == *fContext.fVec3_Type);
1323 }
1324 break;
1325 case SpvDimCube: // fall through
1326 case SpvDimRect: // fall through
1327 case SpvDimBuffer: // fall through
1328 case SpvDimSubpassData:
1329 break;
1330 }
ethannicholasd598f792016-07-25 10:08:54 -07001331 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001332 SpvId sampler = this->writeExpression(*c.fArguments[0], out);
1333 SpvId uv = this->writeExpression(*c.fArguments[1], out);
1334 if (c.fArguments.size() == 3) {
Ethan Nicholas2b3dab62016-11-28 12:03:26 -05001335 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -07001336 SpvImageOperandsBiasMask,
1337 this->writeExpression(*c.fArguments[2], out),
1338 out);
1339 } else {
1340 ASSERT(c.fArguments.size() == 2);
Ethan Nicholas2b3dab62016-11-28 12:03:26 -05001341 this->writeInstruction(op, type, result, sampler, uv,
ethannicholasb3058bd2016-07-01 08:22:01 -07001342 out);
1343 }
1344 break;
1345 }
Greg Daniel64773e62016-11-22 09:44:03 -05001346 case kSubpassLoad_SpecialIntrinsic: {
1347 SpvId img = this->writeExpression(*c.fArguments[0], out);
1348 std::vector<std::unique_ptr<Expression>> args;
1349 args.emplace_back(new FloatLiteral(fContext, Position(), 0.0));
1350 args.emplace_back(new FloatLiteral(fContext, Position(), 0.0));
1351 Constructor ctor(Position(), *fContext.fVec2_Type, std::move(args));
1352 SpvId coords = this->writeConstantVector(ctor);
1353 if (1 == c.fArguments.size()) {
1354 this->writeInstruction(SpvOpImageRead,
1355 this->getType(c.fType),
1356 result,
1357 img,
1358 coords,
1359 out);
1360 } else {
1361 SkASSERT(2 == c.fArguments.size());
1362 SpvId sample = this->writeExpression(*c.fArguments[1], out);
1363 this->writeInstruction(SpvOpImageRead,
1364 this->getType(c.fType),
1365 result,
1366 img,
1367 coords,
1368 SpvImageOperandsSampleMask,
1369 sample,
1370 out);
1371 }
1372 break;
1373 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001374 }
1375 return result;
1376}
1377
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001378SpvId SPIRVCodeGenerator::writeFunctionCall(const FunctionCall& c, SkWStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001379 const auto& entry = fFunctionMap.find(&c.fFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07001380 if (entry == fFunctionMap.end()) {
1381 return this->writeIntrinsicCall(c, out);
1382 }
1383 // stores (variable, type, lvalue) pairs to extract and save after the function call is complete
1384 std::vector<std::tuple<SpvId, SpvId, std::unique_ptr<LValue>>> lvalues;
1385 std::vector<SpvId> arguments;
1386 for (size_t i = 0; i < c.fArguments.size(); i++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001387 // id of temporary variable that we will use to hold this argument, or 0 if it is being
ethannicholasb3058bd2016-07-01 08:22:01 -07001388 // passed directly
1389 SpvId tmpVar;
1390 // if we need a temporary var to store this argument, this is the value to store in the var
1391 SpvId tmpValueId;
ethannicholasd598f792016-07-25 10:08:54 -07001392 if (is_out(*c.fFunction.fParameters[i])) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001393 std::unique_ptr<LValue> lv = this->getLValue(*c.fArguments[i], out);
1394 SpvId ptr = lv->getPointer();
1395 if (ptr) {
1396 arguments.push_back(ptr);
1397 continue;
1398 } else {
1399 // lvalue cannot simply be read and written via a pointer (e.g. a swizzle). Need to
1400 // copy it into a temp, call the function, read the value out of the temp, and then
1401 // update the lvalue.
1402 tmpValueId = lv->load(out);
1403 tmpVar = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001404 lvalues.push_back(std::make_tuple(tmpVar, this->getType(c.fArguments[i]->fType),
ethannicholasb3058bd2016-07-01 08:22:01 -07001405 std::move(lv)));
1406 }
1407 } else {
1408 // see getFunctionType for an explanation of why we're always using pointer parameters
1409 tmpValueId = this->writeExpression(*c.fArguments[i], out);
1410 tmpVar = this->nextId();
1411 }
Greg Daniel64773e62016-11-22 09:44:03 -05001412 this->writeInstruction(SpvOpVariable,
1413 this->getPointerType(c.fArguments[i]->fType,
ethannicholasb3058bd2016-07-01 08:22:01 -07001414 SpvStorageClassFunction),
Greg Daniel64773e62016-11-22 09:44:03 -05001415 tmpVar,
ethannicholasb3058bd2016-07-01 08:22:01 -07001416 SpvStorageClassFunction,
ethannicholasd598f792016-07-25 10:08:54 -07001417 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001418 this->writeInstruction(SpvOpStore, tmpVar, tmpValueId, out);
1419 arguments.push_back(tmpVar);
1420 }
1421 SpvId result = this->nextId();
1422 this->writeOpCode(SpvOpFunctionCall, 4 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001423 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001424 this->writeWord(result, out);
1425 this->writeWord(entry->second, out);
1426 for (SpvId id : arguments) {
1427 this->writeWord(id, out);
1428 }
1429 // now that the call is complete, we may need to update some lvalues with the new values of out
1430 // arguments
1431 for (const auto& tuple : lvalues) {
1432 SpvId load = this->nextId();
1433 this->writeInstruction(SpvOpLoad, std::get<1>(tuple), load, std::get<0>(tuple), out);
1434 std::get<2>(tuple)->store(load, out);
1435 }
1436 return result;
1437}
1438
ethannicholasf789b382016-08-03 12:43:36 -07001439SpvId SPIRVCodeGenerator::writeConstantVector(const Constructor& c) {
ethannicholasd598f792016-07-25 10:08:54 -07001440 ASSERT(c.fType.kind() == Type::kVector_Kind && c.isConstant());
ethannicholasb3058bd2016-07-01 08:22:01 -07001441 SpvId result = this->nextId();
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], fConstantBuffer));
1445 }
ethannicholasd598f792016-07-25 10:08:54 -07001446 SpvId type = this->getType(c.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07001447 if (c.fArguments.size() == 1) {
1448 // with a single argument, a vector will have all of its entries equal to the argument
ethannicholasd598f792016-07-25 10:08:54 -07001449 this->writeOpCode(SpvOpConstantComposite, 3 + c.fType.columns(), fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001450 this->writeWord(type, fConstantBuffer);
1451 this->writeWord(result, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07001452 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001453 this->writeWord(arguments[0], fConstantBuffer);
1454 }
1455 } else {
Greg Daniel64773e62016-11-22 09:44:03 -05001456 this->writeOpCode(SpvOpConstantComposite, 3 + (int32_t) c.fArguments.size(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001457 fConstantBuffer);
1458 this->writeWord(type, fConstantBuffer);
1459 this->writeWord(result, fConstantBuffer);
1460 for (SpvId id : arguments) {
1461 this->writeWord(id, fConstantBuffer);
1462 }
1463 }
1464 return result;
1465}
1466
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001467SpvId SPIRVCodeGenerator::writeFloatConstructor(const Constructor& c, SkWStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001468 ASSERT(c.fType == *fContext.fFloat_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001469 ASSERT(c.fArguments.size() == 1);
ethannicholasd598f792016-07-25 10:08:54 -07001470 ASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001471 SpvId result = this->nextId();
1472 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
ethannicholasd598f792016-07-25 10:08:54 -07001473 if (c.fArguments[0]->fType == *fContext.fInt_Type) {
Greg Daniel64773e62016-11-22 09:44:03 -05001474 this->writeInstruction(SpvOpConvertSToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001475 out);
ethannicholasd598f792016-07-25 10:08:54 -07001476 } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) {
Greg Daniel64773e62016-11-22 09:44:03 -05001477 this->writeInstruction(SpvOpConvertUToF, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001478 out);
ethannicholasd598f792016-07-25 10:08:54 -07001479 } else if (c.fArguments[0]->fType == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001480 return parameter;
1481 }
1482 return result;
1483}
1484
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001485SpvId SPIRVCodeGenerator::writeIntConstructor(const Constructor& c, SkWStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001486 ASSERT(c.fType == *fContext.fInt_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07001487 ASSERT(c.fArguments.size() == 1);
ethannicholasd598f792016-07-25 10:08:54 -07001488 ASSERT(c.fArguments[0]->fType.isNumber());
ethannicholasb3058bd2016-07-01 08:22:01 -07001489 SpvId result = this->nextId();
1490 SpvId parameter = this->writeExpression(*c.fArguments[0], out);
ethannicholasd598f792016-07-25 10:08:54 -07001491 if (c.fArguments[0]->fType == *fContext.fFloat_Type) {
Greg Daniel64773e62016-11-22 09:44:03 -05001492 this->writeInstruction(SpvOpConvertFToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001493 out);
ethannicholasd598f792016-07-25 10:08:54 -07001494 } else if (c.fArguments[0]->fType == *fContext.fUInt_Type) {
Greg Daniel64773e62016-11-22 09:44:03 -05001495 this->writeInstruction(SpvOpSatConvertUToS, this->getType(c.fType), result, parameter,
ethannicholasb3058bd2016-07-01 08:22:01 -07001496 out);
ethannicholasd598f792016-07-25 10:08:54 -07001497 } else if (c.fArguments[0]->fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001498 return parameter;
1499 }
1500 return result;
1501}
1502
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001503SpvId SPIRVCodeGenerator::writeMatrixConstructor(const Constructor& c, SkWStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001504 ASSERT(c.fType.kind() == Type::kMatrix_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001505 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1506 // an instruction
1507 std::vector<SpvId> arguments;
1508 for (size_t i = 0; i < c.fArguments.size(); i++) {
1509 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1510 }
1511 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001512 int rows = c.fType.rows();
1513 int columns = c.fType.columns();
ethannicholasb3058bd2016-07-01 08:22:01 -07001514 // FIXME this won't work to create a matrix from another matrix
1515 if (arguments.size() == 1) {
Greg Daniel64773e62016-11-22 09:44:03 -05001516 // with a single argument, a matrix will have all of its diagonal entries equal to the
ethannicholasb3058bd2016-07-01 08:22:01 -07001517 // argument and its other values equal to zero
1518 // FIXME this won't work for int matrices
ethannicholasd598f792016-07-25 10:08:54 -07001519 FloatLiteral zero(fContext, Position(), 0);
ethannicholasb3058bd2016-07-01 08:22:01 -07001520 SpvId zeroId = this->writeFloatLiteral(zero);
1521 std::vector<SpvId> columnIds;
1522 for (int column = 0; column < columns; column++) {
Greg Daniel64773e62016-11-22 09:44:03 -05001523 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.rows(),
ethannicholasb3058bd2016-07-01 08:22:01 -07001524 out);
Greg Daniel64773e62016-11-22 09:44:03 -05001525 this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows, 1)),
ethannicholasd598f792016-07-25 10:08:54 -07001526 out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001527 SpvId columnId = this->nextId();
1528 this->writeWord(columnId, out);
1529 columnIds.push_back(columnId);
ethannicholasd598f792016-07-25 10:08:54 -07001530 for (int row = 0; row < c.fType.columns(); row++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001531 this->writeWord(row == column ? arguments[0] : zeroId, out);
1532 }
1533 }
Greg Daniel64773e62016-11-22 09:44:03 -05001534 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns,
ethannicholasb3058bd2016-07-01 08:22:01 -07001535 out);
ethannicholasd598f792016-07-25 10:08:54 -07001536 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001537 this->writeWord(result, out);
1538 for (SpvId id : columnIds) {
1539 this->writeWord(id, out);
1540 }
1541 } else {
1542 std::vector<SpvId> columnIds;
1543 int currentCount = 0;
1544 for (size_t i = 0; i < arguments.size(); i++) {
ethannicholasd598f792016-07-25 10:08:54 -07001545 if (c.fArguments[i]->fType.kind() == Type::kVector_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001546 ASSERT(currentCount == 0);
1547 columnIds.push_back(arguments[i]);
1548 currentCount = 0;
1549 } else {
ethannicholasd598f792016-07-25 10:08:54 -07001550 ASSERT(c.fArguments[i]->fType.kind() == Type::kScalar_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001551 if (currentCount == 0) {
ethannicholasd598f792016-07-25 10:08:54 -07001552 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.rows(), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001553 this->writeWord(this->getType(c.fType.componentType().toCompound(fContext, rows,
1554 1)),
ethannicholasb3058bd2016-07-01 08:22:01 -07001555 out);
1556 SpvId id = this->nextId();
1557 this->writeWord(id, out);
1558 columnIds.push_back(id);
1559 }
1560 this->writeWord(arguments[i], out);
1561 currentCount = (currentCount + 1) % rows;
1562 }
1563 }
1564 ASSERT(columnIds.size() == (size_t) columns);
1565 this->writeOpCode(SpvOpCompositeConstruct, 3 + columns, out);
ethannicholasd598f792016-07-25 10:08:54 -07001566 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001567 this->writeWord(result, out);
1568 for (SpvId id : columnIds) {
1569 this->writeWord(id, out);
1570 }
1571 }
1572 return result;
1573}
1574
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001575SpvId SPIRVCodeGenerator::writeVectorConstructor(const Constructor& c, SkWStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001576 ASSERT(c.fType.kind() == Type::kVector_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07001577 if (c.isConstant()) {
1578 return this->writeConstantVector(c);
1579 }
1580 // go ahead and write the arguments so we don't try to write new instructions in the middle of
1581 // an instruction
1582 std::vector<SpvId> arguments;
1583 for (size_t i = 0; i < c.fArguments.size(); i++) {
1584 arguments.push_back(this->writeExpression(*c.fArguments[i], out));
1585 }
1586 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001587 if (arguments.size() == 1 && c.fArguments[0]->fType.kind() == Type::kScalar_Kind) {
1588 this->writeOpCode(SpvOpCompositeConstruct, 3 + c.fType.columns(), out);
1589 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001590 this->writeWord(result, out);
ethannicholasd598f792016-07-25 10:08:54 -07001591 for (int i = 0; i < c.fType.columns(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001592 this->writeWord(arguments[0], out);
1593 }
1594 } else {
1595 this->writeOpCode(SpvOpCompositeConstruct, 3 + (int32_t) c.fArguments.size(), out);
ethannicholasd598f792016-07-25 10:08:54 -07001596 this->writeWord(this->getType(c.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001597 this->writeWord(result, out);
1598 for (SpvId id : arguments) {
1599 this->writeWord(id, out);
1600 }
1601 }
1602 return result;
1603}
1604
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001605SpvId SPIRVCodeGenerator::writeConstructor(const Constructor& c, SkWStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07001606 if (c.fType == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001607 return this->writeFloatConstructor(c, out);
ethannicholasd598f792016-07-25 10:08:54 -07001608 } else if (c.fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001609 return this->writeIntConstructor(c, out);
1610 }
ethannicholasd598f792016-07-25 10:08:54 -07001611 switch (c.fType.kind()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001612 case Type::kVector_Kind:
1613 return this->writeVectorConstructor(c, out);
1614 case Type::kMatrix_Kind:
1615 return this->writeMatrixConstructor(c, out);
1616 default:
1617 ABORT("unsupported constructor: %s", c.description().c_str());
1618 }
1619}
1620
1621SpvStorageClass_ get_storage_class(const Modifiers& modifiers) {
1622 if (modifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001623 ASSERT(!modifiers.fLayout.fPushConstant);
ethannicholasb3058bd2016-07-01 08:22:01 -07001624 return SpvStorageClassInput;
1625 } else if (modifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001626 ASSERT(!modifiers.fLayout.fPushConstant);
ethannicholasb3058bd2016-07-01 08:22:01 -07001627 return SpvStorageClassOutput;
1628 } else if (modifiers.fFlags & Modifiers::kUniform_Flag) {
ethannicholas8ac838d2016-11-22 08:39:36 -08001629 if (modifiers.fLayout.fPushConstant) {
1630 return SpvStorageClassPushConstant;
1631 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001632 return SpvStorageClassUniform;
1633 } else {
1634 return SpvStorageClassFunction;
1635 }
1636}
1637
ethannicholasf789b382016-08-03 12:43:36 -07001638SpvStorageClass_ get_storage_class(const Expression& expr) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001639 switch (expr.fKind) {
1640 case Expression::kVariableReference_Kind:
ethannicholasd598f792016-07-25 10:08:54 -07001641 return get_storage_class(((VariableReference&) expr).fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07001642 case Expression::kFieldAccess_Kind:
1643 return get_storage_class(*((FieldAccess&) expr).fBase);
1644 case Expression::kIndex_Kind:
1645 return get_storage_class(*((IndexExpression&) expr).fBase);
1646 default:
1647 return SpvStorageClassFunction;
1648 }
1649}
1650
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001651std::vector<SpvId> SPIRVCodeGenerator::getAccessChain(const Expression& expr, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001652 std::vector<SpvId> chain;
1653 switch (expr.fKind) {
1654 case Expression::kIndex_Kind: {
1655 IndexExpression& indexExpr = (IndexExpression&) expr;
1656 chain = this->getAccessChain(*indexExpr.fBase, out);
1657 chain.push_back(this->writeExpression(*indexExpr.fIndex, out));
1658 break;
1659 }
1660 case Expression::kFieldAccess_Kind: {
1661 FieldAccess& fieldExpr = (FieldAccess&) expr;
1662 chain = this->getAccessChain(*fieldExpr.fBase, out);
ethannicholasd598f792016-07-25 10:08:54 -07001663 IntLiteral index(fContext, Position(), fieldExpr.fFieldIndex);
ethannicholasb3058bd2016-07-01 08:22:01 -07001664 chain.push_back(this->writeIntLiteral(index));
1665 break;
1666 }
1667 default:
1668 chain.push_back(this->getLValue(expr, out)->getPointer());
1669 }
1670 return chain;
1671}
1672
1673class PointerLValue : public SPIRVCodeGenerator::LValue {
1674public:
Greg Daniel64773e62016-11-22 09:44:03 -05001675 PointerLValue(SPIRVCodeGenerator& gen, SpvId pointer, SpvId type)
ethannicholasb3058bd2016-07-01 08:22:01 -07001676 : fGen(gen)
1677 , fPointer(pointer)
1678 , fType(type) {}
1679
1680 virtual SpvId getPointer() override {
1681 return fPointer;
1682 }
1683
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001684 virtual SpvId load(SkWStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001685 SpvId result = fGen.nextId();
1686 fGen.writeInstruction(SpvOpLoad, fType, result, fPointer, out);
1687 return result;
1688 }
1689
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001690 virtual void store(SpvId value, SkWStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001691 fGen.writeInstruction(SpvOpStore, fPointer, value, out);
1692 }
1693
1694private:
1695 SPIRVCodeGenerator& fGen;
1696 const SpvId fPointer;
1697 const SpvId fType;
1698};
1699
1700class SwizzleLValue : public SPIRVCodeGenerator::LValue {
1701public:
Greg Daniel64773e62016-11-22 09:44:03 -05001702 SwizzleLValue(SPIRVCodeGenerator& gen, SpvId vecPointer, const std::vector<int>& components,
ethannicholasb3058bd2016-07-01 08:22:01 -07001703 const Type& baseType, const Type& swizzleType)
1704 : fGen(gen)
1705 , fVecPointer(vecPointer)
1706 , fComponents(components)
1707 , fBaseType(baseType)
1708 , fSwizzleType(swizzleType) {}
1709
1710 virtual SpvId getPointer() override {
1711 return 0;
1712 }
1713
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001714 virtual SpvId load(SkWStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001715 SpvId base = fGen.nextId();
1716 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1717 SpvId result = fGen.nextId();
1718 fGen.writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) fComponents.size(), out);
1719 fGen.writeWord(fGen.getType(fSwizzleType), out);
1720 fGen.writeWord(result, out);
1721 fGen.writeWord(base, out);
1722 fGen.writeWord(base, out);
1723 for (int component : fComponents) {
1724 fGen.writeWord(component, out);
1725 }
1726 return result;
1727 }
1728
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001729 virtual void store(SpvId value, SkWStream& out) override {
ethannicholasb3058bd2016-07-01 08:22:01 -07001730 // use OpVectorShuffle to mix and match the vector components. We effectively create
1731 // a virtual vector out of the concatenation of the left and right vectors, and then
Greg Daniel64773e62016-11-22 09:44:03 -05001732 // select components from this virtual vector to make the result vector. For
ethannicholasb3058bd2016-07-01 08:22:01 -07001733 // instance, given:
1734 // vec3 L = ...;
1735 // vec3 R = ...;
1736 // L.xz = R.xy;
Greg Daniel64773e62016-11-22 09:44:03 -05001737 // we end up with the virtual vector (L.x, L.y, L.z, R.x, R.y, R.z). Then we want
ethannicholasb3058bd2016-07-01 08:22:01 -07001738 // our result vector to look like (R.x, L.y, R.y), so we need to select indices
1739 // (3, 1, 4).
1740 SpvId base = fGen.nextId();
1741 fGen.writeInstruction(SpvOpLoad, fGen.getType(fBaseType), base, fVecPointer, out);
1742 SpvId shuffle = fGen.nextId();
1743 fGen.writeOpCode(SpvOpVectorShuffle, 5 + fBaseType.columns(), out);
1744 fGen.writeWord(fGen.getType(fBaseType), out);
1745 fGen.writeWord(shuffle, out);
1746 fGen.writeWord(base, out);
1747 fGen.writeWord(value, out);
1748 for (int i = 0; i < fBaseType.columns(); i++) {
1749 // current offset into the virtual vector, defaults to pulling the unmodified
1750 // value from the left side
1751 int offset = i;
1752 // check to see if we are writing this component
1753 for (size_t j = 0; j < fComponents.size(); j++) {
1754 if (fComponents[j] == i) {
Greg Daniel64773e62016-11-22 09:44:03 -05001755 // we're writing to this component, so adjust the offset to pull from
ethannicholasb3058bd2016-07-01 08:22:01 -07001756 // the correct component of the right side instead of preserving the
1757 // value from the left
1758 offset = (int) (j + fBaseType.columns());
1759 break;
1760 }
1761 }
1762 fGen.writeWord(offset, out);
1763 }
1764 fGen.writeInstruction(SpvOpStore, fVecPointer, shuffle, out);
1765 }
1766
1767private:
1768 SPIRVCodeGenerator& fGen;
1769 const SpvId fVecPointer;
1770 const std::vector<int>& fComponents;
1771 const Type& fBaseType;
1772 const Type& fSwizzleType;
1773};
1774
Greg Daniel64773e62016-11-22 09:44:03 -05001775std::unique_ptr<SPIRVCodeGenerator::LValue> SPIRVCodeGenerator::getLValue(const Expression& expr,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001776 SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001777 switch (expr.fKind) {
1778 case Expression::kVariableReference_Kind: {
ethannicholasd598f792016-07-25 10:08:54 -07001779 const Variable& var = ((VariableReference&) expr).fVariable;
1780 auto entry = fVariableMap.find(&var);
ethannicholasb3058bd2016-07-01 08:22:01 -07001781 ASSERT(entry != fVariableMap.end());
1782 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1783 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001784 entry->second,
ethannicholasd598f792016-07-25 10:08:54 -07001785 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001786 }
1787 case Expression::kIndex_Kind: // fall through
1788 case Expression::kFieldAccess_Kind: {
1789 std::vector<SpvId> chain = this->getAccessChain(expr, out);
1790 SpvId member = this->nextId();
1791 this->writeOpCode(SpvOpAccessChain, (SpvId) (3 + chain.size()), out);
Greg Daniel64773e62016-11-22 09:44:03 -05001792 this->writeWord(this->getPointerType(expr.fType, get_storage_class(expr)), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001793 this->writeWord(member, out);
1794 for (SpvId idx : chain) {
1795 this->writeWord(idx, out);
1796 }
1797 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1798 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001799 member,
ethannicholasd598f792016-07-25 10:08:54 -07001800 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001801 }
1802
1803 case Expression::kSwizzle_Kind: {
1804 Swizzle& swizzle = (Swizzle&) expr;
1805 size_t count = swizzle.fComponents.size();
1806 SpvId base = this->getLValue(*swizzle.fBase, out)->getPointer();
1807 ASSERT(base);
1808 if (count == 1) {
ethannicholasd598f792016-07-25 10:08:54 -07001809 IntLiteral index(fContext, Position(), swizzle.fComponents[0]);
ethannicholasb3058bd2016-07-01 08:22:01 -07001810 SpvId member = this->nextId();
1811 this->writeInstruction(SpvOpAccessChain,
Greg Daniel64773e62016-11-22 09:44:03 -05001812 this->getPointerType(swizzle.fType,
1813 get_storage_class(*swizzle.fBase)),
1814 member,
1815 base,
1816 this->writeIntLiteral(index),
ethannicholasb3058bd2016-07-01 08:22:01 -07001817 out);
1818 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1819 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001820 member,
ethannicholasd598f792016-07-25 10:08:54 -07001821 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001822 } else {
1823 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new SwizzleLValue(
Greg Daniel64773e62016-11-22 09:44:03 -05001824 *this,
1825 base,
1826 swizzle.fComponents,
ethannicholasd598f792016-07-25 10:08:54 -07001827 swizzle.fBase->fType,
1828 expr.fType));
ethannicholasb3058bd2016-07-01 08:22:01 -07001829 }
1830 }
1831
1832 default:
1833 // expr isn't actually an lvalue, create a dummy variable for it. This case happens due
Greg Daniel64773e62016-11-22 09:44:03 -05001834 // to the need to store values in temporary variables during function calls (see
ethannicholasb3058bd2016-07-01 08:22:01 -07001835 // comments in getFunctionType); erroneous uses of rvalues as lvalues should have been
1836 // caught by IRGenerator
1837 SpvId result = this->nextId();
1838 SpvId type = this->getPointerType(expr.fType, SpvStorageClassFunction);
ethannicholasd598f792016-07-25 10:08:54 -07001839 this->writeInstruction(SpvOpVariable, type, result, SpvStorageClassFunction,
1840 fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07001841 this->writeInstruction(SpvOpStore, result, this->writeExpression(expr, out), out);
1842 return std::unique_ptr<SPIRVCodeGenerator::LValue>(new PointerLValue(
1843 *this,
Greg Daniel64773e62016-11-22 09:44:03 -05001844 result,
ethannicholasd598f792016-07-25 10:08:54 -07001845 this->getType(expr.fType)));
ethannicholasb3058bd2016-07-01 08:22:01 -07001846 }
1847}
1848
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001849SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, SkWStream& out) {
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001850 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001851 auto entry = fVariableMap.find(&ref.fVariable);
ethannicholasb3058bd2016-07-01 08:22:01 -07001852 ASSERT(entry != fVariableMap.end());
1853 SpvId var = entry->second;
ethannicholasd598f792016-07-25 10:08:54 -07001854 this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001855 if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN &&
1856 fProgram.fSettings.fFlipY) {
1857 // need to remap to a top-left coordinate system
1858 if (fRTHeightStructId == (SpvId) -1) {
1859 // height variable hasn't been written yet
1860 std::shared_ptr<SymbolTable> st(new SymbolTable(fErrors));
1861 ASSERT(fRTHeightFieldIndex == (SpvId) -1);
1862 std::vector<Type::Field> fields;
1863 fields.emplace_back(Modifiers(), SkString(SKSL_RTHEIGHT_NAME),
1864 fContext.fFloat_Type.get());
1865 SkString name("sksl_synthetic_uniforms");
1866 Type intfStruct(Position(), name, fields);
1867 Layout layout(-1, -1, 1, -1, -1, -1, -1, false, false, false, Layout::Format::kUnspecified,
1868 false);
1869 Variable intfVar(Position(), Modifiers(layout, Modifiers::kUniform_Flag), name,
1870 intfStruct, Variable::kGlobal_Storage);
1871 InterfaceBlock intf(Position(), intfVar, st);
1872 fRTHeightStructId = this->writeInterfaceBlock(intf);
1873 fRTHeightFieldIndex = 0;
1874 }
1875 ASSERT(fRTHeightFieldIndex != (SpvId) -1);
1876 // write vec4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, 1.0)
1877 SpvId xId = this->nextId();
1878 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId,
1879 result, 0, out);
1880 IntLiteral fieldIndex(fContext, Position(), fRTHeightFieldIndex);
1881 SpvId fieldIndexId = this->writeIntLiteral(fieldIndex);
Ethan Nicholas613a6972016-12-29 16:36:40 -05001882 SpvId heightPtr = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001883 this->writeOpCode(SpvOpAccessChain, 5, out);
1884 this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out);
Ethan Nicholas613a6972016-12-29 16:36:40 -05001885 this->writeWord(heightPtr, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001886 this->writeWord(fRTHeightStructId, out);
1887 this->writeWord(fieldIndexId, out);
Ethan Nicholas613a6972016-12-29 16:36:40 -05001888 SpvId heightRead = this->nextId();
1889 this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead,
1890 heightPtr, out);
Ethan Nicholas941e7e22016-12-12 15:33:30 -05001891 SpvId rawYId = this->nextId();
1892 this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId,
1893 result, 1, out);
1894 SpvId flippedYId = this->nextId();
1895 this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId,
1896 heightRead, rawYId, out);
1897 FloatLiteral zero(fContext, Position(), 0.0);
1898 SpvId zeroId = writeFloatLiteral(zero);
1899 FloatLiteral one(fContext, Position(), 1.0);
1900 SpvId oneId = writeFloatLiteral(one);
1901 SpvId flipped = this->nextId();
1902 this->writeOpCode(SpvOpCompositeConstruct, 7, out);
1903 this->writeWord(this->getType(*fContext.fVec4_Type), out);
1904 this->writeWord(flipped, out);
1905 this->writeWord(xId, out);
1906 this->writeWord(flippedYId, out);
1907 this->writeWord(zeroId, out);
1908 this->writeWord(oneId, out);
1909 return flipped;
1910 }
ethannicholasb3058bd2016-07-01 08:22:01 -07001911 return result;
1912}
1913
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001914SpvId SPIRVCodeGenerator::writeIndexExpression(const IndexExpression& expr, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001915 return getLValue(expr, out)->load(out);
1916}
1917
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001918SpvId SPIRVCodeGenerator::writeFieldAccess(const FieldAccess& f, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001919 return getLValue(f, out)->load(out);
1920}
1921
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001922SpvId SPIRVCodeGenerator::writeSwizzle(const Swizzle& swizzle, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001923 SpvId base = this->writeExpression(*swizzle.fBase, out);
1924 SpvId result = this->nextId();
1925 size_t count = swizzle.fComponents.size();
1926 if (count == 1) {
Greg Daniel64773e62016-11-22 09:44:03 -05001927 this->writeInstruction(SpvOpCompositeExtract, this->getType(swizzle.fType), result, base,
1928 swizzle.fComponents[0], out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001929 } else {
1930 this->writeOpCode(SpvOpVectorShuffle, 5 + (int32_t) count, out);
ethannicholasd598f792016-07-25 10:08:54 -07001931 this->writeWord(this->getType(swizzle.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07001932 this->writeWord(result, out);
1933 this->writeWord(base, out);
1934 this->writeWord(base, out);
1935 for (int component : swizzle.fComponents) {
1936 this->writeWord(component, out);
1937 }
1938 }
1939 return result;
1940}
1941
Greg Daniel64773e62016-11-22 09:44:03 -05001942SpvId SPIRVCodeGenerator::writeBinaryOperation(const Type& resultType,
1943 const Type& operandType, SpvId lhs,
1944 SpvId rhs, SpvOp_ ifFloat, SpvOp_ ifInt,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001945 SpvOp_ ifUInt, SpvOp_ ifBool, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001946 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07001947 if (is_float(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001948 this->writeInstruction(ifFloat, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001949 } else if (is_signed(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001950 this->writeInstruction(ifInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001951 } else if (is_unsigned(fContext, operandType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001952 this->writeInstruction(ifUInt, this->getType(resultType), result, lhs, rhs, out);
ethannicholasd598f792016-07-25 10:08:54 -07001953 } else if (operandType == *fContext.fBool_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001954 this->writeInstruction(ifBool, this->getType(resultType), result, lhs, rhs, out);
1955 } else {
1956 ABORT("invalid operandType: %s", operandType.description().c_str());
1957 }
1958 return result;
1959}
1960
1961bool is_assignment(Token::Kind op) {
1962 switch (op) {
1963 case Token::EQ: // fall through
1964 case Token::PLUSEQ: // fall through
1965 case Token::MINUSEQ: // fall through
1966 case Token::STAREQ: // fall through
1967 case Token::SLASHEQ: // fall through
1968 case Token::PERCENTEQ: // fall through
1969 case Token::SHLEQ: // fall through
1970 case Token::SHREQ: // fall through
1971 case Token::BITWISEOREQ: // fall through
1972 case Token::BITWISEXOREQ: // fall through
1973 case Token::BITWISEANDEQ: // fall through
1974 case Token::LOGICALOREQ: // fall through
1975 case Token::LOGICALXOREQ: // fall through
1976 case Token::LOGICALANDEQ:
1977 return true;
1978 default:
1979 return false;
1980 }
1981}
1982
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05001983SpvId SPIRVCodeGenerator::writeBinaryExpression(const BinaryExpression& b, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07001984 // handle cases where we don't necessarily evaluate both LHS and RHS
1985 switch (b.fOperator) {
1986 case Token::EQ: {
1987 SpvId rhs = this->writeExpression(*b.fRight, out);
1988 this->getLValue(*b.fLeft, out)->store(rhs, out);
1989 return rhs;
1990 }
1991 case Token::LOGICALAND:
1992 return this->writeLogicalAnd(b, out);
1993 case Token::LOGICALOR:
1994 return this->writeLogicalOr(b, out);
1995 default:
1996 break;
1997 }
1998
1999 // "normal" operators
ethannicholasd598f792016-07-25 10:08:54 -07002000 const Type& resultType = b.fType;
ethannicholasb3058bd2016-07-01 08:22:01 -07002001 std::unique_ptr<LValue> lvalue;
2002 SpvId lhs;
2003 if (is_assignment(b.fOperator)) {
2004 lvalue = this->getLValue(*b.fLeft, out);
2005 lhs = lvalue->load(out);
2006 } else {
2007 lvalue = nullptr;
2008 lhs = this->writeExpression(*b.fLeft, out);
2009 }
2010 SpvId rhs = this->writeExpression(*b.fRight, out);
2011 // component type we are operating on: float, int, uint
2012 const Type* operandType;
2013 // IR allows mismatched types in expressions (e.g. vec2 * float), but they need special handling
2014 // in SPIR-V
2015 if (b.fLeft->fType != b.fRight->fType) {
Greg Daniel64773e62016-11-22 09:44:03 -05002016 if (b.fLeft->fType.kind() == Type::kVector_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002017 b.fRight->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002018 // promote number to vector
2019 SpvId vec = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002020 this->writeOpCode(SpvOpCompositeConstruct, 3 + b.fType.columns(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002021 this->writeWord(this->getType(resultType), out);
2022 this->writeWord(vec, out);
2023 for (int i = 0; i < resultType.columns(); i++) {
2024 this->writeWord(rhs, out);
2025 }
2026 rhs = vec;
ethannicholasd598f792016-07-25 10:08:54 -07002027 operandType = &b.fRight->fType;
Greg Daniel64773e62016-11-22 09:44:03 -05002028 } else if (b.fRight->fType.kind() == Type::kVector_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002029 b.fLeft->fType.isNumber()) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002030 // promote number to vector
2031 SpvId vec = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002032 this->writeOpCode(SpvOpCompositeConstruct, 3 + b.fType.columns(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002033 this->writeWord(this->getType(resultType), out);
2034 this->writeWord(vec, out);
2035 for (int i = 0; i < resultType.columns(); i++) {
2036 this->writeWord(lhs, out);
2037 }
2038 lhs = vec;
2039 ASSERT(!lvalue);
ethannicholasd598f792016-07-25 10:08:54 -07002040 operandType = &b.fLeft->fType;
2041 } else if (b.fLeft->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002042 SpvOp_ op;
ethannicholasd598f792016-07-25 10:08:54 -07002043 if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002044 op = SpvOpMatrixTimesMatrix;
ethannicholasd598f792016-07-25 10:08:54 -07002045 } else if (b.fRight->fType.kind() == Type::kVector_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002046 op = SpvOpMatrixTimesVector;
2047 } else {
ethannicholasd598f792016-07-25 10:08:54 -07002048 ASSERT(b.fRight->fType.kind() == Type::kScalar_Kind);
ethannicholasb3058bd2016-07-01 08:22:01 -07002049 op = SpvOpMatrixTimesScalar;
2050 }
2051 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002052 this->writeInstruction(op, this->getType(b.fType), result, lhs, rhs, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002053 if (b.fOperator == Token::STAREQ) {
2054 lvalue->store(result, out);
2055 } else {
2056 ASSERT(b.fOperator == Token::STAR);
2057 }
2058 return result;
ethannicholasd598f792016-07-25 10:08:54 -07002059 } else if (b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002060 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002061 if (b.fLeft->fType.kind() == Type::kVector_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05002062 this->writeInstruction(SpvOpVectorTimesMatrix, this->getType(b.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002063 lhs, rhs, out);
2064 } else {
ethannicholasd598f792016-07-25 10:08:54 -07002065 ASSERT(b.fLeft->fType.kind() == Type::kScalar_Kind);
Greg Daniel64773e62016-11-22 09:44:03 -05002066 this->writeInstruction(SpvOpMatrixTimesScalar, this->getType(b.fType), result, rhs,
ethannicholasb3058bd2016-07-01 08:22:01 -07002067 lhs, out);
2068 }
2069 if (b.fOperator == Token::STAREQ) {
2070 lvalue->store(result, out);
2071 } else {
2072 ASSERT(b.fOperator == Token::STAR);
2073 }
2074 return result;
2075 } else {
2076 ABORT("unsupported binary expression: %s", b.description().c_str());
2077 }
2078 } else {
ethannicholasd598f792016-07-25 10:08:54 -07002079 operandType = &b.fLeft->fType;
2080 ASSERT(*operandType == b.fRight->fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002081 }
2082 switch (b.fOperator) {
2083 case Token::EQEQ:
ethannicholasd598f792016-07-25 10:08:54 -07002084 ASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002085 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002086 SpvOpIEqual, SpvOpIEqual, SpvOpLogicalEqual, out);
2087 case Token::NEQ:
ethannicholasd598f792016-07-25 10:08:54 -07002088 ASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002089 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdNotEqual,
2090 SpvOpINotEqual, SpvOpINotEqual, SpvOpLogicalNotEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002091 out);
2092 case Token::GT:
ethannicholasd598f792016-07-25 10:08:54 -07002093 ASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002094 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2095 SpvOpFOrdGreaterThan, SpvOpSGreaterThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002096 SpvOpUGreaterThan, SpvOpUndef, out);
2097 case Token::LT:
ethannicholasd598f792016-07-25 10:08:54 -07002098 ASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002099 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFOrdLessThan,
ethannicholasb3058bd2016-07-01 08:22:01 -07002100 SpvOpSLessThan, SpvOpULessThan, SpvOpUndef, out);
2101 case Token::GTEQ:
ethannicholasd598f792016-07-25 10:08:54 -07002102 ASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002103 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2104 SpvOpFOrdGreaterThanEqual, SpvOpSGreaterThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002105 SpvOpUGreaterThanEqual, SpvOpUndef, out);
2106 case Token::LTEQ:
ethannicholasd598f792016-07-25 10:08:54 -07002107 ASSERT(resultType == *fContext.fBool_Type);
Greg Daniel64773e62016-11-22 09:44:03 -05002108 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs,
2109 SpvOpFOrdLessThanEqual, SpvOpSLessThanEqual,
ethannicholasb3058bd2016-07-01 08:22:01 -07002110 SpvOpULessThanEqual, SpvOpUndef, out);
2111 case Token::PLUS:
Greg Daniel64773e62016-11-22 09:44:03 -05002112 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002113 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2114 case Token::MINUS:
Greg Daniel64773e62016-11-22 09:44:03 -05002115 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002116 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2117 case Token::STAR:
Greg Daniel64773e62016-11-22 09:44:03 -05002118 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002119 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002120 // matrix multiply
2121 SpvId result = this->nextId();
2122 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2123 lhs, rhs, out);
2124 return result;
2125 }
Greg Daniel64773e62016-11-22 09:44:03 -05002126 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002127 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2128 case Token::SLASH:
Greg Daniel64773e62016-11-22 09:44:03 -05002129 return this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002130 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
2131 case Token::PLUSEQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002132 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002133 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2134 ASSERT(lvalue);
2135 lvalue->store(result, out);
2136 return result;
2137 }
2138 case Token::MINUSEQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002139 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002140 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2141 ASSERT(lvalue);
2142 lvalue->store(result, out);
2143 return result;
2144 }
2145 case Token::STAREQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002146 if (b.fLeft->fType.kind() == Type::kMatrix_Kind &&
ethannicholasd598f792016-07-25 10:08:54 -07002147 b.fRight->fType.kind() == Type::kMatrix_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002148 // matrix multiply
2149 SpvId result = this->nextId();
2150 this->writeInstruction(SpvOpMatrixTimesMatrix, this->getType(resultType), result,
2151 lhs, rhs, out);
2152 ASSERT(lvalue);
2153 lvalue->store(result, out);
2154 return result;
2155 }
Greg Daniel64773e62016-11-22 09:44:03 -05002156 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFMul,
ethannicholasb3058bd2016-07-01 08:22:01 -07002157 SpvOpIMul, SpvOpIMul, SpvOpUndef, out);
2158 ASSERT(lvalue);
2159 lvalue->store(result, out);
2160 return result;
2161 }
2162 case Token::SLASHEQ: {
Greg Daniel64773e62016-11-22 09:44:03 -05002163 SpvId result = this->writeBinaryOperation(resultType, *operandType, lhs, rhs, SpvOpFDiv,
ethannicholasb3058bd2016-07-01 08:22:01 -07002164 SpvOpSDiv, SpvOpUDiv, SpvOpUndef, out);
2165 ASSERT(lvalue);
2166 lvalue->store(result, out);
2167 return result;
2168 }
2169 default:
2170 // FIXME: missing support for some operators (bitwise, &&=, ||=, shift...)
2171 ABORT("unsupported binary expression: %s", b.description().c_str());
2172 }
2173}
2174
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002175SpvId SPIRVCodeGenerator::writeLogicalAnd(const BinaryExpression& a, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002176 ASSERT(a.fOperator == Token::LOGICALAND);
ethannicholasd598f792016-07-25 10:08:54 -07002177 BoolLiteral falseLiteral(fContext, Position(), false);
ethannicholasb3058bd2016-07-01 08:22:01 -07002178 SpvId falseConstant = this->writeBoolLiteral(falseLiteral);
2179 SpvId lhs = this->writeExpression(*a.fLeft, out);
2180 SpvId rhsLabel = this->nextId();
2181 SpvId end = this->nextId();
2182 SpvId lhsBlock = fCurrentBlock;
2183 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2184 this->writeInstruction(SpvOpBranchConditional, lhs, rhsLabel, end, out);
2185 this->writeLabel(rhsLabel, out);
2186 SpvId rhs = this->writeExpression(*a.fRight, out);
2187 SpvId rhsBlock = fCurrentBlock;
2188 this->writeInstruction(SpvOpBranch, end, out);
2189 this->writeLabel(end, out);
2190 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002191 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, falseConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002192 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002193 return result;
2194}
2195
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002196SpvId SPIRVCodeGenerator::writeLogicalOr(const BinaryExpression& o, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002197 ASSERT(o.fOperator == Token::LOGICALOR);
ethannicholasd598f792016-07-25 10:08:54 -07002198 BoolLiteral trueLiteral(fContext, Position(), true);
ethannicholasb3058bd2016-07-01 08:22:01 -07002199 SpvId trueConstant = this->writeBoolLiteral(trueLiteral);
2200 SpvId lhs = this->writeExpression(*o.fLeft, out);
2201 SpvId rhsLabel = this->nextId();
2202 SpvId end = this->nextId();
2203 SpvId lhsBlock = fCurrentBlock;
2204 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2205 this->writeInstruction(SpvOpBranchConditional, lhs, end, rhsLabel, out);
2206 this->writeLabel(rhsLabel, out);
2207 SpvId rhs = this->writeExpression(*o.fRight, out);
2208 SpvId rhsBlock = fCurrentBlock;
2209 this->writeInstruction(SpvOpBranch, end, out);
2210 this->writeLabel(end, out);
2211 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002212 this->writeInstruction(SpvOpPhi, this->getType(*fContext.fBool_Type), result, trueConstant,
ethannicholasd598f792016-07-25 10:08:54 -07002213 lhsBlock, rhs, rhsBlock, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002214 return result;
2215}
2216
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002217SpvId SPIRVCodeGenerator::writeTernaryExpression(const TernaryExpression& t, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002218 SpvId test = this->writeExpression(*t.fTest, out);
2219 if (t.fIfTrue->isConstant() && t.fIfFalse->isConstant()) {
2220 // both true and false are constants, can just use OpSelect
2221 SpvId result = this->nextId();
2222 SpvId trueId = this->writeExpression(*t.fIfTrue, out);
2223 SpvId falseId = this->writeExpression(*t.fIfFalse, out);
Greg Daniel64773e62016-11-22 09:44:03 -05002224 this->writeInstruction(SpvOpSelect, this->getType(t.fType), result, test, trueId, falseId,
ethannicholasb3058bd2016-07-01 08:22:01 -07002225 out);
2226 return result;
2227 }
Greg Daniel64773e62016-11-22 09:44:03 -05002228 // was originally using OpPhi to choose the result, but for some reason that is crashing on
ethannicholasb3058bd2016-07-01 08:22:01 -07002229 // Adreno. Switched to storing the result in a temp variable as glslang does.
2230 SpvId var = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002231 this->writeInstruction(SpvOpVariable, this->getPointerType(t.fType, SpvStorageClassFunction),
ethannicholasd598f792016-07-25 10:08:54 -07002232 var, SpvStorageClassFunction, fVariableBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002233 SpvId trueLabel = this->nextId();
2234 SpvId falseLabel = this->nextId();
2235 SpvId end = this->nextId();
2236 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2237 this->writeInstruction(SpvOpBranchConditional, test, trueLabel, falseLabel, out);
2238 this->writeLabel(trueLabel, out);
2239 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfTrue, out), out);
2240 this->writeInstruction(SpvOpBranch, end, out);
2241 this->writeLabel(falseLabel, out);
2242 this->writeInstruction(SpvOpStore, var, this->writeExpression(*t.fIfFalse, out), out);
2243 this->writeInstruction(SpvOpBranch, end, out);
2244 this->writeLabel(end, out);
2245 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002246 this->writeInstruction(SpvOpLoad, this->getType(t.fType), result, var, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002247 return result;
2248}
2249
ethannicholasd598f792016-07-25 10:08:54 -07002250std::unique_ptr<Expression> create_literal_1(const Context& context, const Type& type) {
2251 if (type == *context.fInt_Type) {
2252 return std::unique_ptr<Expression>(new IntLiteral(context, Position(), 1));
ethannicholasb3058bd2016-07-01 08:22:01 -07002253 }
ethannicholasd598f792016-07-25 10:08:54 -07002254 else if (type == *context.fFloat_Type) {
2255 return std::unique_ptr<Expression>(new FloatLiteral(context, Position(), 1.0));
ethannicholasb3058bd2016-07-01 08:22:01 -07002256 } else {
2257 ABORT("math is unsupported on type '%s'")
2258 }
2259}
2260
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002261SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002262 if (p.fOperator == Token::MINUS) {
2263 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002264 SpvId typeId = this->getType(p.fType);
ethannicholasb3058bd2016-07-01 08:22:01 -07002265 SpvId expr = this->writeExpression(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002266 if (is_float(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002267 this->writeInstruction(SpvOpFNegate, typeId, result, expr, out);
ethannicholasd598f792016-07-25 10:08:54 -07002268 } else if (is_signed(fContext, p.fType)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002269 this->writeInstruction(SpvOpSNegate, typeId, result, expr, out);
2270 } else {
2271 ABORT("unsupported prefix expression %s", p.description().c_str());
2272 };
2273 return result;
2274 }
2275 switch (p.fOperator) {
2276 case Token::PLUS:
2277 return this->writeExpression(*p.fOperand, out);
2278 case Token::PLUSPLUS: {
2279 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002280 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002281 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2282 SpvOpFAdd, SpvOpIAdd, SpvOpIAdd, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002283 out);
2284 lv->store(result, out);
2285 return result;
2286 }
2287 case Token::MINUSMINUS: {
2288 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
ethannicholasd598f792016-07-25 10:08:54 -07002289 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
Greg Daniel64773e62016-11-22 09:44:03 -05002290 SpvId result = this->writeBinaryOperation(p.fType, p.fType, lv->load(out), one,
2291 SpvOpFSub, SpvOpISub, SpvOpISub, SpvOpUndef,
ethannicholasb3058bd2016-07-01 08:22:01 -07002292 out);
2293 lv->store(result, out);
2294 return result;
2295 }
ethannicholas5961bc92016-10-12 06:39:56 -07002296 case Token::LOGICALNOT: {
ethannicholasd598f792016-07-25 10:08:54 -07002297 ASSERT(p.fOperand->fType == *fContext.fBool_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002298 SpvId result = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002299 this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002300 this->writeExpression(*p.fOperand, out), out);
2301 return result;
2302 }
ethannicholas5961bc92016-10-12 06:39:56 -07002303 case Token::BITWISENOT: {
2304 SpvId result = this->nextId();
2305 this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
2306 this->writeExpression(*p.fOperand, out), out);
2307 return result;
2308 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002309 default:
2310 ABORT("unsupported prefix expression: %s", p.description().c_str());
2311 }
2312}
2313
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002314SpvId SPIRVCodeGenerator::writePostfixExpression(const PostfixExpression& p, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002315 std::unique_ptr<LValue> lv = this->getLValue(*p.fOperand, out);
2316 SpvId result = lv->load(out);
ethannicholasd598f792016-07-25 10:08:54 -07002317 SpvId one = this->writeExpression(*create_literal_1(fContext, p.fType), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002318 switch (p.fOperator) {
2319 case Token::PLUSPLUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002320 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFAdd,
ethannicholasb3058bd2016-07-01 08:22:01 -07002321 SpvOpIAdd, SpvOpIAdd, SpvOpUndef, out);
2322 lv->store(temp, out);
2323 return result;
2324 }
2325 case Token::MINUSMINUS: {
Greg Daniel64773e62016-11-22 09:44:03 -05002326 SpvId temp = this->writeBinaryOperation(p.fType, p.fType, result, one, SpvOpFSub,
ethannicholasb3058bd2016-07-01 08:22:01 -07002327 SpvOpISub, SpvOpISub, SpvOpUndef, out);
2328 lv->store(temp, out);
2329 return result;
2330 }
2331 default:
2332 ABORT("unsupported postfix expression %s", p.description().c_str());
2333 }
2334}
2335
ethannicholasf789b382016-08-03 12:43:36 -07002336SpvId SPIRVCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002337 if (b.fValue) {
2338 if (fBoolTrue == 0) {
2339 fBoolTrue = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002340 this->writeInstruction(SpvOpConstantTrue, this->getType(b.fType), fBoolTrue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002341 fConstantBuffer);
2342 }
2343 return fBoolTrue;
2344 } else {
2345 if (fBoolFalse == 0) {
2346 fBoolFalse = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002347 this->writeInstruction(SpvOpConstantFalse, this->getType(b.fType), fBoolFalse,
ethannicholasb3058bd2016-07-01 08:22:01 -07002348 fConstantBuffer);
2349 }
2350 return fBoolFalse;
2351 }
2352}
2353
ethannicholasf789b382016-08-03 12:43:36 -07002354SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) {
ethannicholasd598f792016-07-25 10:08:54 -07002355 if (i.fType == *fContext.fInt_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002356 auto entry = fIntConstants.find(i.fValue);
2357 if (entry == fIntConstants.end()) {
2358 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002359 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002360 fConstantBuffer);
2361 fIntConstants[i.fValue] = result;
2362 return result;
2363 }
2364 return entry->second;
2365 } else {
ethannicholasd598f792016-07-25 10:08:54 -07002366 ASSERT(i.fType == *fContext.fUInt_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002367 auto entry = fUIntConstants.find(i.fValue);
2368 if (entry == fUIntConstants.end()) {
2369 SpvId result = this->nextId();
Greg Daniel64773e62016-11-22 09:44:03 -05002370 this->writeInstruction(SpvOpConstant, this->getType(i.fType), result, (SpvId) i.fValue,
ethannicholasb3058bd2016-07-01 08:22:01 -07002371 fConstantBuffer);
2372 fUIntConstants[i.fValue] = result;
2373 return result;
2374 }
2375 return entry->second;
2376 }
2377}
2378
ethannicholasf789b382016-08-03 12:43:36 -07002379SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
ethannicholasd598f792016-07-25 10:08:54 -07002380 if (f.fType == *fContext.fFloat_Type) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002381 float value = (float) f.fValue;
2382 auto entry = fFloatConstants.find(value);
2383 if (entry == fFloatConstants.end()) {
2384 SpvId result = this->nextId();
2385 uint32_t bits;
2386 ASSERT(sizeof(bits) == sizeof(value));
2387 memcpy(&bits, &value, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002388 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits,
ethannicholasb3058bd2016-07-01 08:22:01 -07002389 fConstantBuffer);
2390 fFloatConstants[value] = result;
2391 return result;
2392 }
2393 return entry->second;
2394 } else {
ethannicholasd598f792016-07-25 10:08:54 -07002395 ASSERT(f.fType == *fContext.fDouble_Type);
ethannicholasb3058bd2016-07-01 08:22:01 -07002396 auto entry = fDoubleConstants.find(f.fValue);
2397 if (entry == fDoubleConstants.end()) {
2398 SpvId result = this->nextId();
2399 uint64_t bits;
2400 ASSERT(sizeof(bits) == sizeof(f.fValue));
2401 memcpy(&bits, &f.fValue, sizeof(bits));
Greg Daniel64773e62016-11-22 09:44:03 -05002402 this->writeInstruction(SpvOpConstant, this->getType(f.fType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002403 bits & 0xffffffff, bits >> 32, fConstantBuffer);
2404 fDoubleConstants[f.fValue] = result;
2405 return result;
2406 }
2407 return entry->second;
2408 }
2409}
2410
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002411SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, SkWStream& out) {
ethannicholasd598f792016-07-25 10:08:54 -07002412 SpvId result = fFunctionMap[&f];
Greg Daniel64773e62016-11-22 09:44:03 -05002413 this->writeInstruction(SpvOpFunction, this->getType(f.fReturnType), result,
ethannicholasb3058bd2016-07-01 08:22:01 -07002414 SpvFunctionControlMaskNone, this->getFunctionType(f), out);
ethannicholasd598f792016-07-25 10:08:54 -07002415 this->writeInstruction(SpvOpName, result, f.fName.c_str(), fNameBuffer);
2416 for (size_t i = 0; i < f.fParameters.size(); i++) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002417 SpvId id = this->nextId();
ethannicholasd598f792016-07-25 10:08:54 -07002418 fVariableMap[f.fParameters[i]] = id;
ethannicholasb3058bd2016-07-01 08:22:01 -07002419 SpvId type;
ethannicholasd598f792016-07-25 10:08:54 -07002420 type = this->getPointerType(f.fParameters[i]->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002421 this->writeInstruction(SpvOpFunctionParameter, type, id, out);
2422 }
2423 return result;
2424}
2425
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002426SpvId SPIRVCodeGenerator::writeFunction(const FunctionDefinition& f, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002427 SpvId result = this->writeFunctionStart(f.fDeclaration, out);
2428 this->writeLabel(this->nextId(), out);
ethannicholasd598f792016-07-25 10:08:54 -07002429 if (f.fDeclaration.fName == "main") {
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002430 write_data(*fGlobalInitializersBuffer.detachAsData(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002431 }
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002432 SkDynamicMemoryWStream bodyBuffer;
ethannicholasb3058bd2016-07-01 08:22:01 -07002433 this->writeBlock(*f.fBody, bodyBuffer);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002434 write_data(*fVariableBuffer.detachAsData(), out);
2435 write_data(*bodyBuffer.detachAsData(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002436 if (fCurrentBlock) {
2437 this->writeInstruction(SpvOpReturn, out);
2438 }
2439 this->writeInstruction(SpvOpFunctionEnd, out);
2440 return result;
2441}
2442
2443void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
2444 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002445 this->writeInstruction(SpvOpDecorate, target, SpvDecorationLocation, layout.fLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002446 fDecorationBuffer);
2447 }
2448 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002449 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBinding, layout.fBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002450 fDecorationBuffer);
2451 }
2452 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002453 this->writeInstruction(SpvOpDecorate, target, SpvDecorationIndex, layout.fIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002454 fDecorationBuffer);
2455 }
2456 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002457 this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002458 fDecorationBuffer);
2459 }
Greg Daniel64773e62016-11-22 09:44:03 -05002460 if (layout.fInputAttachmentIndex >= 0) {
2461 this->writeInstruction(SpvOpDecorate, target, SpvDecorationInputAttachmentIndex,
2462 layout.fInputAttachmentIndex, fDecorationBuffer);
2463 }
ethannicholas5961bc92016-10-12 06:39:56 -07002464 if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN) {
Greg Daniel64773e62016-11-22 09:44:03 -05002465 this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
ethannicholasb3058bd2016-07-01 08:22:01 -07002466 fDecorationBuffer);
2467 }
2468}
2469
2470void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target, int member) {
2471 if (layout.fLocation >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002472 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationLocation,
ethannicholasb3058bd2016-07-01 08:22:01 -07002473 layout.fLocation, fDecorationBuffer);
2474 }
2475 if (layout.fBinding >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002476 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBinding,
ethannicholasb3058bd2016-07-01 08:22:01 -07002477 layout.fBinding, fDecorationBuffer);
2478 }
2479 if (layout.fIndex >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002480 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationIndex,
ethannicholasb3058bd2016-07-01 08:22:01 -07002481 layout.fIndex, fDecorationBuffer);
2482 }
2483 if (layout.fSet >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002484 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationDescriptorSet,
ethannicholasb3058bd2016-07-01 08:22:01 -07002485 layout.fSet, fDecorationBuffer);
2486 }
Greg Daniel64773e62016-11-22 09:44:03 -05002487 if (layout.fInputAttachmentIndex >= 0) {
2488 this->writeInstruction(SpvOpDecorate, target, member, SpvDecorationInputAttachmentIndex,
2489 layout.fInputAttachmentIndex, fDecorationBuffer);
2490 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002491 if (layout.fBuiltin >= 0) {
Greg Daniel64773e62016-11-22 09:44:03 -05002492 this->writeInstruction(SpvOpMemberDecorate, target, member, SpvDecorationBuiltIn,
ethannicholasb3058bd2016-07-01 08:22:01 -07002493 layout.fBuiltin, fDecorationBuffer);
2494 }
2495}
2496
ethannicholasf789b382016-08-03 12:43:36 -07002497SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
ethannicholas8ac838d2016-11-22 08:39:36 -08002498 MemoryLayout layout = intf.fVariable.fModifiers.fLayout.fPushConstant ?
2499 MemoryLayout(MemoryLayout::k430_Standard) :
2500 fDefaultLayout;
ethannicholasb3058bd2016-07-01 08:22:01 -07002501 SpvId result = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002502 const Type* type = &intf.fVariable.fType;
2503 if (fProgram.fInputs.fRTHeight) {
2504 ASSERT(fRTHeightStructId == (SpvId) -1);
2505 ASSERT(fRTHeightFieldIndex == (SpvId) -1);
2506 std::vector<Type::Field> fields = type->fields();
2507 fRTHeightStructId = result;
2508 fRTHeightFieldIndex = fields.size();
2509 fields.emplace_back(Modifiers(), SkString(SKSL_RTHEIGHT_NAME), fContext.fFloat_Type.get());
2510 type = new Type(type->fPosition, type->name(), fields);
2511 }
2512 SpvId typeId = this->getType(*type, layout);
2513 this->writeInstruction(SpvOpDecorate, typeId, SpvDecorationBlock, fDecorationBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002514 SpvStorageClass_ storageClass = get_storage_class(intf.fVariable.fModifiers);
ethannicholasb3058bd2016-07-01 08:22:01 -07002515 SpvId ptrType = this->nextId();
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002516 this->writeInstruction(SpvOpTypePointer, ptrType, storageClass, typeId, fConstantBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002517 this->writeInstruction(SpvOpVariable, ptrType, result, storageClass, fConstantBuffer);
ethannicholasd598f792016-07-25 10:08:54 -07002518 this->writeLayout(intf.fVariable.fModifiers.fLayout, result);
2519 fVariableMap[&intf.fVariable] = result;
ethannicholasb3058bd2016-07-01 08:22:01 -07002520 return result;
2521}
2522
ethannicholas5961bc92016-10-12 06:39:56 -07002523#define BUILTIN_IGNORE 9999
Greg Daniel64773e62016-11-22 09:44:03 -05002524void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002525 SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002526 for (size_t i = 0; i < decl.fVars.size(); i++) {
ethannicholas14fe8cc2016-09-07 13:37:16 -07002527 const VarDeclaration& varDecl = decl.fVars[i];
2528 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002529 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2530 // in the OpenGL backend.
2531 ASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
2532 Modifiers::kWriteOnly_Flag |
2533 Modifiers::kCoherent_Flag |
2534 Modifiers::kVolatile_Flag |
2535 Modifiers::kRestrict_Flag)));
ethannicholas5961bc92016-10-12 06:39:56 -07002536 if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
2537 continue;
2538 }
2539 if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
2540 kind != Program::kFragment_Kind) {
2541 continue;
2542 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002543 if (!var->fIsReadFrom && !var->fIsWrittenTo &&
2544 !(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
2545 Modifiers::kOut_Flag |
2546 Modifiers::kUniform_Flag))) {
ethannicholasd598f792016-07-25 10:08:54 -07002547 // variable is dead and not an input / output var (the Vulkan debug layers complain if
2548 // we elide an interface var, even if it's dead)
ethannicholasb3058bd2016-07-01 08:22:01 -07002549 continue;
2550 }
2551 SpvStorageClass_ storageClass;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002552 if (var->fModifiers.fFlags & Modifiers::kIn_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002553 storageClass = SpvStorageClassInput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002554 } else if (var->fModifiers.fFlags & Modifiers::kOut_Flag) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002555 storageClass = SpvStorageClassOutput;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002556 } else if (var->fModifiers.fFlags & Modifiers::kUniform_Flag) {
2557 if (var->fType.kind() == Type::kSampler_Kind) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002558 storageClass = SpvStorageClassUniformConstant;
2559 } else {
2560 storageClass = SpvStorageClassUniform;
2561 }
2562 } else {
2563 storageClass = SpvStorageClassPrivate;
2564 }
2565 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002566 fVariableMap[var] = id;
2567 SpvId type = this->getPointerType(var->fType, storageClass);
ethannicholasb3058bd2016-07-01 08:22:01 -07002568 this->writeInstruction(SpvOpVariable, type, id, storageClass, fConstantBuffer);
ethannicholas14fe8cc2016-09-07 13:37:16 -07002569 this->writeInstruction(SpvOpName, id, var->fName.c_str(), fNameBuffer);
2570 if (var->fType.kind() == Type::kMatrix_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05002571 this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationColMajor,
ethannicholasb3058bd2016-07-01 08:22:01 -07002572 fDecorationBuffer);
Greg Daniel64773e62016-11-22 09:44:03 -05002573 this->writeInstruction(SpvOpMemberDecorate, id, (SpvId) i, SpvDecorationMatrixStride,
ethannicholas8ac838d2016-11-22 08:39:36 -08002574 (SpvId) fDefaultLayout.stride(var->fType), fDecorationBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002575 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002576 if (varDecl.fValue) {
ethannicholasf789b382016-08-03 12:43:36 -07002577 ASSERT(!fCurrentBlock);
2578 fCurrentBlock = -1;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002579 SpvId value = this->writeExpression(*varDecl.fValue, fGlobalInitializersBuffer);
ethannicholasb3058bd2016-07-01 08:22:01 -07002580 this->writeInstruction(SpvOpStore, id, value, fGlobalInitializersBuffer);
ethannicholasf789b382016-08-03 12:43:36 -07002581 fCurrentBlock = 0;
ethannicholasb3058bd2016-07-01 08:22:01 -07002582 }
ethannicholas14fe8cc2016-09-07 13:37:16 -07002583 this->writeLayout(var->fModifiers.fLayout, id);
ethannicholasb3058bd2016-07-01 08:22:01 -07002584 }
2585}
2586
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002587void SPIRVCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, SkWStream& out) {
ethannicholas14fe8cc2016-09-07 13:37:16 -07002588 for (const auto& varDecl : decl.fVars) {
2589 const Variable* var = varDecl.fVar;
Brian Salomonf9f45122016-11-29 11:59:17 -05002590 // These haven't been implemented in our SPIR-V generator yet and we only currently use them
2591 // in the OpenGL backend.
2592 ASSERT(!(var->fModifiers.fFlags & (Modifiers::kReadOnly_Flag |
2593 Modifiers::kWriteOnly_Flag |
2594 Modifiers::kCoherent_Flag |
2595 Modifiers::kVolatile_Flag |
2596 Modifiers::kRestrict_Flag)));
ethannicholasb3058bd2016-07-01 08:22:01 -07002597 SpvId id = this->nextId();
ethannicholas14fe8cc2016-09-07 13:37:16 -07002598 fVariableMap[var] = id;
2599 SpvId type = this->getPointerType(var->fType, SpvStorageClassFunction);
ethannicholasb3058bd2016-07-01 08:22:01 -07002600 this->writeInstruction(SpvOpVariable, type, id, SpvStorageClassFunction, fVariableBuffer);
ethannicholas14fe8cc2016-09-07 13:37:16 -07002601 this->writeInstruction(SpvOpName, id, var->fName.c_str(), fNameBuffer);
2602 if (varDecl.fValue) {
2603 SpvId value = this->writeExpression(*varDecl.fValue, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002604 this->writeInstruction(SpvOpStore, id, value, out);
2605 }
2606 }
2607}
2608
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002609void SPIRVCodeGenerator::writeStatement(const Statement& s, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002610 switch (s.fKind) {
2611 case Statement::kBlock_Kind:
2612 this->writeBlock((Block&) s, out);
2613 break;
2614 case Statement::kExpression_Kind:
2615 this->writeExpression(*((ExpressionStatement&) s).fExpression, out);
2616 break;
Greg Daniel64773e62016-11-22 09:44:03 -05002617 case Statement::kReturn_Kind:
ethannicholasb3058bd2016-07-01 08:22:01 -07002618 this->writeReturnStatement((ReturnStatement&) s, out);
2619 break;
ethannicholas14fe8cc2016-09-07 13:37:16 -07002620 case Statement::kVarDeclarations_Kind:
2621 this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002622 break;
2623 case Statement::kIf_Kind:
2624 this->writeIfStatement((IfStatement&) s, out);
2625 break;
2626 case Statement::kFor_Kind:
2627 this->writeForStatement((ForStatement&) s, out);
2628 break;
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002629 case Statement::kWhile_Kind:
2630 this->writeWhileStatement((WhileStatement&) s, out);
2631 break;
2632 case Statement::kDo_Kind:
2633 this->writeDoStatement((DoStatement&) s, out);
2634 break;
ethannicholasb3058bd2016-07-01 08:22:01 -07002635 case Statement::kBreak_Kind:
2636 this->writeInstruction(SpvOpBranch, fBreakTarget.top(), out);
2637 break;
2638 case Statement::kContinue_Kind:
2639 this->writeInstruction(SpvOpBranch, fContinueTarget.top(), out);
2640 break;
2641 case Statement::kDiscard_Kind:
2642 this->writeInstruction(SpvOpKill, out);
2643 break;
2644 default:
2645 ABORT("unsupported statement: %s", s.description().c_str());
2646 }
2647}
2648
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002649void SPIRVCodeGenerator::writeBlock(const Block& b, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002650 for (size_t i = 0; i < b.fStatements.size(); i++) {
2651 this->writeStatement(*b.fStatements[i], out);
2652 }
2653}
2654
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002655void SPIRVCodeGenerator::writeIfStatement(const IfStatement& stmt, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002656 SpvId test = this->writeExpression(*stmt.fTest, out);
2657 SpvId ifTrue = this->nextId();
2658 SpvId ifFalse = this->nextId();
2659 if (stmt.fIfFalse) {
2660 SpvId end = this->nextId();
2661 this->writeInstruction(SpvOpSelectionMerge, end, SpvSelectionControlMaskNone, out);
2662 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2663 this->writeLabel(ifTrue, out);
2664 this->writeStatement(*stmt.fIfTrue, out);
2665 if (fCurrentBlock) {
2666 this->writeInstruction(SpvOpBranch, end, out);
2667 }
2668 this->writeLabel(ifFalse, out);
2669 this->writeStatement(*stmt.fIfFalse, out);
2670 if (fCurrentBlock) {
2671 this->writeInstruction(SpvOpBranch, end, out);
2672 }
2673 this->writeLabel(end, out);
2674 } else {
2675 this->writeInstruction(SpvOpSelectionMerge, ifFalse, SpvSelectionControlMaskNone, out);
2676 this->writeInstruction(SpvOpBranchConditional, test, ifTrue, ifFalse, out);
2677 this->writeLabel(ifTrue, out);
2678 this->writeStatement(*stmt.fIfTrue, out);
2679 if (fCurrentBlock) {
2680 this->writeInstruction(SpvOpBranch, ifFalse, out);
2681 }
2682 this->writeLabel(ifFalse, out);
2683 }
2684}
2685
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002686void SPIRVCodeGenerator::writeForStatement(const ForStatement& f, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002687 if (f.fInitializer) {
2688 this->writeStatement(*f.fInitializer, out);
2689 }
2690 SpvId header = this->nextId();
2691 SpvId start = this->nextId();
2692 SpvId body = this->nextId();
2693 SpvId next = this->nextId();
2694 fContinueTarget.push(next);
2695 SpvId end = this->nextId();
2696 fBreakTarget.push(end);
2697 this->writeInstruction(SpvOpBranch, header, out);
2698 this->writeLabel(header, out);
2699 this->writeInstruction(SpvOpLoopMerge, end, next, SpvLoopControlMaskNone, out);
ethannicholasf789b382016-08-03 12:43:36 -07002700 this->writeInstruction(SpvOpBranch, start, out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002701 this->writeLabel(start, out);
ethannicholas22f939e2016-10-13 13:25:34 -07002702 if (f.fTest) {
2703 SpvId test = this->writeExpression(*f.fTest, out);
2704 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2705 }
ethannicholasb3058bd2016-07-01 08:22:01 -07002706 this->writeLabel(body, out);
2707 this->writeStatement(*f.fStatement, out);
2708 if (fCurrentBlock) {
2709 this->writeInstruction(SpvOpBranch, next, out);
2710 }
2711 this->writeLabel(next, out);
2712 if (f.fNext) {
2713 this->writeExpression(*f.fNext, out);
2714 }
2715 this->writeInstruction(SpvOpBranch, header, out);
2716 this->writeLabel(end, out);
2717 fBreakTarget.pop();
2718 fContinueTarget.pop();
2719}
2720
Ethan Nicholasfd146aa2017-01-13 16:40:35 -05002721void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, SkWStream& out) {
2722 // We believe the while loop code below will work, but Skia doesn't actually use them and
2723 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2724 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2725 // message, simply remove the error call below to see whether our while loop support actually
2726 // works.
2727 fErrors.error(w.fPosition, "internal error: while loop support has been disabled in SPIR-V, "
2728 "see SkSLSPIRVCodeGenerator.cpp for details");
2729
2730 SpvId header = this->nextId();
2731 SpvId start = this->nextId();
2732 SpvId body = this->nextId();
2733 fContinueTarget.push(start);
2734 SpvId end = this->nextId();
2735 fBreakTarget.push(end);
2736 this->writeInstruction(SpvOpBranch, header, out);
2737 this->writeLabel(header, out);
2738 this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out);
2739 this->writeInstruction(SpvOpBranch, start, out);
2740 this->writeLabel(start, out);
2741 SpvId test = this->writeExpression(*w.fTest, out);
2742 this->writeInstruction(SpvOpBranchConditional, test, body, end, out);
2743 this->writeLabel(body, out);
2744 this->writeStatement(*w.fStatement, out);
2745 if (fCurrentBlock) {
2746 this->writeInstruction(SpvOpBranch, start, out);
2747 }
2748 this->writeLabel(end, out);
2749 fBreakTarget.pop();
2750 fContinueTarget.pop();
2751}
2752
2753void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, SkWStream& out) {
2754 // We believe the do loop code below will work, but Skia doesn't actually use them and
2755 // adequately testing this code in the absence of Skia exercising it isn't straightforward. For
2756 // the time being, we just fail with an error due to the lack of testing. If you encounter this
2757 // message, simply remove the error call below to see whether our do loop support actually
2758 // works.
2759 fErrors.error(d.fPosition, "internal error: do loop support has been disabled in SPIR-V, see "
2760 "SkSLSPIRVCodeGenerator.cpp for details");
2761
2762 SpvId header = this->nextId();
2763 SpvId start = this->nextId();
2764 SpvId next = this->nextId();
2765 fContinueTarget.push(next);
2766 SpvId end = this->nextId();
2767 fBreakTarget.push(end);
2768 this->writeInstruction(SpvOpBranch, header, out);
2769 this->writeLabel(header, out);
2770 this->writeInstruction(SpvOpLoopMerge, end, start, SpvLoopControlMaskNone, out);
2771 this->writeInstruction(SpvOpBranch, start, out);
2772 this->writeLabel(start, out);
2773 this->writeStatement(*d.fStatement, out);
2774 if (fCurrentBlock) {
2775 this->writeInstruction(SpvOpBranch, next, out);
2776 }
2777 this->writeLabel(next, out);
2778 SpvId test = this->writeExpression(*d.fTest, out);
2779 this->writeInstruction(SpvOpBranchConditional, test, start, end, out);
2780 this->writeLabel(end, out);
2781 fBreakTarget.pop();
2782 fContinueTarget.pop();
2783}
2784
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002785void SPIRVCodeGenerator::writeReturnStatement(const ReturnStatement& r, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002786 if (r.fExpression) {
Greg Daniel64773e62016-11-22 09:44:03 -05002787 this->writeInstruction(SpvOpReturnValue, this->writeExpression(*r.fExpression, out),
ethannicholasb3058bd2016-07-01 08:22:01 -07002788 out);
2789 } else {
2790 this->writeInstruction(SpvOpReturn, out);
2791 }
2792}
2793
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002794void SPIRVCodeGenerator::writeInstructions(const Program& program, SkWStream& out) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002795 fGLSLExtendedInstructions = this->nextId();
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002796 SkDynamicMemoryWStream body;
ethannicholasb3058bd2016-07-01 08:22:01 -07002797 std::vector<SpvId> interfaceVars;
2798 // assign IDs to functions
2799 for (size_t i = 0; i < program.fElements.size(); i++) {
2800 if (program.fElements[i]->fKind == ProgramElement::kFunction_Kind) {
2801 FunctionDefinition& f = (FunctionDefinition&) *program.fElements[i];
ethannicholasd598f792016-07-25 10:08:54 -07002802 fFunctionMap[&f.fDeclaration] = this->nextId();
ethannicholasb3058bd2016-07-01 08:22:01 -07002803 }
2804 }
2805 for (size_t i = 0; i < program.fElements.size(); i++) {
2806 if (program.fElements[i]->fKind == ProgramElement::kInterfaceBlock_Kind) {
2807 InterfaceBlock& intf = (InterfaceBlock&) *program.fElements[i];
2808 SpvId id = this->writeInterfaceBlock(intf);
ethannicholasd598f792016-07-25 10:08:54 -07002809 if ((intf.fVariable.fModifiers.fFlags & Modifiers::kIn_Flag) ||
2810 (intf.fVariable.fModifiers.fFlags & Modifiers::kOut_Flag)) {
ethannicholasb3058bd2016-07-01 08:22:01 -07002811 interfaceVars.push_back(id);
2812 }
2813 }
2814 }
2815 for (size_t i = 0; i < program.fElements.size(); i++) {
2816 if (program.fElements[i]->fKind == ProgramElement::kVar_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05002817 this->writeGlobalVars(program.fKind, ((VarDeclarations&) *program.fElements[i]),
ethannicholas5961bc92016-10-12 06:39:56 -07002818 body);
ethannicholasb3058bd2016-07-01 08:22:01 -07002819 }
2820 }
2821 for (size_t i = 0; i < program.fElements.size(); i++) {
2822 if (program.fElements[i]->fKind == ProgramElement::kFunction_Kind) {
2823 this->writeFunction(((FunctionDefinition&) *program.fElements[i]), body);
2824 }
2825 }
ethannicholasd598f792016-07-25 10:08:54 -07002826 const FunctionDeclaration* main = nullptr;
ethannicholasb3058bd2016-07-01 08:22:01 -07002827 for (auto entry : fFunctionMap) {
ethannicholasf789b382016-08-03 12:43:36 -07002828 if (entry.first->fName == "main") {
ethannicholasb3058bd2016-07-01 08:22:01 -07002829 main = entry.first;
2830 }
2831 }
2832 ASSERT(main);
2833 for (auto entry : fVariableMap) {
ethannicholasd598f792016-07-25 10:08:54 -07002834 const Variable* var = entry.first;
Greg Daniel64773e62016-11-22 09:44:03 -05002835 if (var->fStorage == Variable::kGlobal_Storage &&
ethannicholasb3058bd2016-07-01 08:22:01 -07002836 ((var->fModifiers.fFlags & Modifiers::kIn_Flag) ||
2837 (var->fModifiers.fFlags & Modifiers::kOut_Flag))) {
2838 interfaceVars.push_back(entry.second);
2839 }
2840 }
2841 this->writeCapabilities(out);
2842 this->writeInstruction(SpvOpExtInstImport, fGLSLExtendedInstructions, "GLSL.std.450", out);
2843 this->writeInstruction(SpvOpMemoryModel, SpvAddressingModelLogical, SpvMemoryModelGLSL450, out);
Greg Daniel64773e62016-11-22 09:44:03 -05002844 this->writeOpCode(SpvOpEntryPoint, (SpvId) (3 + (strlen(main->fName.c_str()) + 4) / 4) +
ethannicholasb3058bd2016-07-01 08:22:01 -07002845 (int32_t) interfaceVars.size(), out);
2846 switch (program.fKind) {
2847 case Program::kVertex_Kind:
2848 this->writeWord(SpvExecutionModelVertex, out);
2849 break;
2850 case Program::kFragment_Kind:
2851 this->writeWord(SpvExecutionModelFragment, out);
2852 break;
2853 }
2854 this->writeWord(fFunctionMap[main], out);
2855 this->writeString(main->fName.c_str(), out);
2856 for (int var : interfaceVars) {
2857 this->writeWord(var, out);
2858 }
2859 if (program.fKind == Program::kFragment_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05002860 this->writeInstruction(SpvOpExecutionMode,
2861 fFunctionMap[main],
ethannicholasb3058bd2016-07-01 08:22:01 -07002862 SpvExecutionModeOriginUpperLeft,
2863 out);
2864 }
2865 for (size_t i = 0; i < program.fElements.size(); i++) {
2866 if (program.fElements[i]->fKind == ProgramElement::kExtension_Kind) {
Greg Daniel64773e62016-11-22 09:44:03 -05002867 this->writeInstruction(SpvOpSourceExtension,
2868 ((Extension&) *program.fElements[i]).fName.c_str(),
ethannicholasb3058bd2016-07-01 08:22:01 -07002869 out);
2870 }
2871 }
Greg Daniel64773e62016-11-22 09:44:03 -05002872
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002873 write_data(*fExtraGlobalsBuffer.detachAsData(), out);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002874 write_data(*fNameBuffer.detachAsData(), out);
2875 write_data(*fDecorationBuffer.detachAsData(), out);
2876 write_data(*fConstantBuffer.detachAsData(), out);
2877 write_data(*fExternalFunctionsBuffer.detachAsData(), out);
2878 write_data(*body.detachAsData(), out);
ethannicholasb3058bd2016-07-01 08:22:01 -07002879}
2880
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002881bool SPIRVCodeGenerator::generateCode() {
2882 ASSERT(!fErrors.errorCount());
2883 this->writeWord(SpvMagicNumber, *fOut);
2884 this->writeWord(SpvVersion, *fOut);
2885 this->writeWord(SKSL_MAGIC, *fOut);
Ethan Nicholas9e1138d2016-11-21 10:39:35 -05002886 SkDynamicMemoryWStream buffer;
Ethan Nicholas941e7e22016-12-12 15:33:30 -05002887 this->writeInstructions(fProgram, buffer);
2888 this->writeWord(fIdCount, *fOut);
2889 this->writeWord(0, *fOut); // reserved, always zero
2890 write_data(*buffer.detachAsData(), *fOut);
2891 return 0 == fErrors.errorCount();
ethannicholasb3058bd2016-07-01 08:22:01 -07002892}
2893
2894}