blob: b27f061d5b3a16b3bbf82cc25f321fd971bbaa26 [file] [log] [blame]
Chris Forbesaf4ed532018-12-06 18:33:27 -08001// Copyright 2018 The SwiftShader Authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include <spirv/unified1/spirv.hpp>
Chris Forbes9667a5b2019-03-07 09:26:48 -080016#include <spirv/unified1/GLSL.std.450.h>
Chris Forbesaf4ed532018-12-06 18:33:27 -080017#include "SpirvShader.hpp"
18#include "System/Math.hpp"
Ben Claytonefec1b92019-03-05 17:38:16 +000019#include "Vulkan/VkBuffer.hpp"
Chris Forbesebe5f7f2019-01-16 10:38:34 -080020#include "Vulkan/VkDebug.hpp"
Ben Clayton76e9bc02019-02-26 15:02:18 +000021#include "Vulkan/VkPipelineLayout.hpp"
Chris Forbesaf4ed532018-12-06 18:33:27 -080022#include "Device/Config.hpp"
23
24namespace sw
25{
26 volatile int SpirvShader::serialCounter = 1; // Start at 1, 0 is invalid shader.
27
Chris Forbes5839dcf2018-12-10 19:02:58 -080028 SpirvShader::SpirvShader(InsnStore const &insns)
29 : insns{insns}, inputs{MAX_INTERFACE_COMPONENTS},
30 outputs{MAX_INTERFACE_COMPONENTS},
31 serialID{serialCounter++}, modes{}
Chris Forbesaf4ed532018-12-06 18:33:27 -080032 {
Ben Clayton45faa082019-03-05 13:20:40 +000033 ASSERT(insns.size() > 0);
34
Chris Forbesaf4ed532018-12-06 18:33:27 -080035 // Simplifying assumptions (to be satisfied by earlier transformations)
Chris Forbesbde34082018-12-28 12:03:10 -080036 // - There is exactly one entrypoint in the module, and it's the one we want
Chris Forbesaf4ed532018-12-06 18:33:27 -080037 // - The only input/output OpVariables present are those used by the entrypoint
38
Chris Forbese57f10e2019-03-04 10:53:07 -080039 // TODO: Add real support for control flow. For now, track whether we've seen
40 // a label or a return already (if so, the shader does things we will mishandle).
41 // We expect there to be one of each in a simple shader -- the first and last instruction
42 // of the entrypoint function.
43 bool seenLabel = false;
44 bool seenReturn = false;
45
Chris Forbes4a979dc2019-01-17 09:36:46 -080046 for (auto insn : *this)
47 {
48 switch (insn.opcode())
49 {
50 case spv::OpExecutionMode:
51 ProcessExecutionMode(insn);
52 break;
Chris Forbesaf4ed532018-12-06 18:33:27 -080053
Chris Forbesc25b8072018-12-10 15:10:39 -080054 case spv::OpDecorate:
55 {
Ben Claytonab51bbf2019-02-20 14:36:27 +000056 TypeOrObjectID targetId = insn.word(1);
Chris Forbes93f70b32019-02-10 21:26:27 +000057 auto decoration = static_cast<spv::Decoration>(insn.word(2));
Chris Forbesc25b8072018-12-10 15:10:39 -080058 decorations[targetId].Apply(
Chris Forbes93f70b32019-02-10 21:26:27 +000059 decoration,
Chris Forbesc25b8072018-12-10 15:10:39 -080060 insn.wordCount() > 3 ? insn.word(3) : 0);
Chris Forbes93f70b32019-02-10 21:26:27 +000061
62 if (decoration == spv::DecorationCentroid)
63 modes.NeedsCentroid = true;
Chris Forbesc25b8072018-12-10 15:10:39 -080064 break;
65 }
66
67 case spv::OpMemberDecorate:
68 {
Ben Claytonab51bbf2019-02-20 14:36:27 +000069 TypeID targetId = insn.word(1);
Chris Forbesc25b8072018-12-10 15:10:39 -080070 auto memberIndex = insn.word(2);
71 auto &d = memberDecorations[targetId];
72 if (memberIndex >= d.size())
73 d.resize(memberIndex + 1); // on demand; exact size would require another pass...
Chris Forbes93f70b32019-02-10 21:26:27 +000074 auto decoration = static_cast<spv::Decoration>(insn.word(3));
Chris Forbesc25b8072018-12-10 15:10:39 -080075 d[memberIndex].Apply(
Chris Forbes93f70b32019-02-10 21:26:27 +000076 decoration,
Chris Forbesc25b8072018-12-10 15:10:39 -080077 insn.wordCount() > 4 ? insn.word(4) : 0);
Chris Forbes93f70b32019-02-10 21:26:27 +000078
79 if (decoration == spv::DecorationCentroid)
80 modes.NeedsCentroid = true;
Chris Forbesc25b8072018-12-10 15:10:39 -080081 break;
82 }
83
84 case spv::OpDecorationGroup:
85 // Nothing to do here. We don't need to record the definition of the group; we'll just have
86 // the bundle of decorations float around. If we were to ever walk the decorations directly,
87 // we might think about introducing this as a real Object.
88 break;
89
90 case spv::OpGroupDecorate:
91 {
92 auto const &srcDecorations = decorations[insn.word(1)];
93 for (auto i = 2u; i < insn.wordCount(); i++)
94 {
95 // remaining operands are targets to apply the group to.
96 decorations[insn.word(i)].Apply(srcDecorations);
97 }
98 break;
99 }
100
101 case spv::OpGroupMemberDecorate:
102 {
103 auto const &srcDecorations = decorations[insn.word(1)];
104 for (auto i = 2u; i < insn.wordCount(); i += 2)
105 {
106 // remaining operands are pairs of <id>, literal for members to apply to.
107 auto &d = memberDecorations[insn.word(i)];
108 auto memberIndex = insn.word(i + 1);
109 if (memberIndex >= d.size())
110 d.resize(memberIndex + 1); // on demand resize, see above...
111 d[memberIndex].Apply(srcDecorations);
112 }
113 break;
114 }
115
Chris Forbese57f10e2019-03-04 10:53:07 -0800116 case spv::OpLabel:
117 if (seenLabel)
118 UNIMPLEMENTED("Shader contains multiple labels, has control flow");
119 seenLabel = true;
120 break;
121
122 case spv::OpReturn:
123 if (seenReturn)
124 UNIMPLEMENTED("Shader contains multiple returns, has control flow");
125 seenReturn = true;
126 break;
127
Chris Forbes4a979dc2019-01-17 09:36:46 -0800128 case spv::OpTypeVoid:
129 case spv::OpTypeBool:
130 case spv::OpTypeInt:
131 case spv::OpTypeFloat:
132 case spv::OpTypeVector:
133 case spv::OpTypeMatrix:
134 case spv::OpTypeImage:
135 case spv::OpTypeSampler:
136 case spv::OpTypeSampledImage:
137 case spv::OpTypeArray:
138 case spv::OpTypeRuntimeArray:
139 case spv::OpTypeStruct:
140 case spv::OpTypePointer:
141 case spv::OpTypeFunction:
Ben Clayton0bb83b82019-02-26 11:41:07 +0000142 DeclareType(insn);
Chris Forbes4a979dc2019-01-17 09:36:46 -0800143 break;
Chris Forbes296aa252018-12-27 11:48:21 -0800144
Chris Forbes4a979dc2019-01-17 09:36:46 -0800145 case spv::OpVariable:
146 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000147 TypeID typeId = insn.word(1);
148 ObjectID resultId = insn.word(2);
Chris Forbes4a979dc2019-01-17 09:36:46 -0800149 auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
150 if (insn.wordCount() > 4)
151 UNIMPLEMENTED("Variable initializers not yet supported");
Chris Forbes296aa252018-12-27 11:48:21 -0800152
Chris Forbes4a979dc2019-01-17 09:36:46 -0800153 auto &object = defs[resultId];
154 object.kind = Object::Kind::Variable;
155 object.definition = insn;
Ben Clayton9a162482019-02-25 11:54:43 +0000156 object.type = typeId;
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000157 object.pointerBase = insn.word(2); // base is itself
Chris Forbesc25b8072018-12-10 15:10:39 -0800158
Ben Claytonefec1b92019-03-05 17:38:16 +0000159 ASSERT(getType(typeId).storageClass == storageClass);
160
161 switch (storageClass)
Chris Forbesc25b8072018-12-10 15:10:39 -0800162 {
Ben Claytonefec1b92019-03-05 17:38:16 +0000163 case spv::StorageClassInput:
164 case spv::StorageClassOutput:
Ben Claytona1924732019-02-28 18:42:10 +0000165 ProcessInterfaceVariable(object);
Ben Claytonefec1b92019-03-05 17:38:16 +0000166 break;
167 case spv::StorageClassUniform:
168 case spv::StorageClassStorageBuffer:
169 object.kind = Object::Kind::PhysicalPointer;
170 break;
171
172 case spv::StorageClassPrivate:
173 case spv::StorageClassFunction:
174 break; // Correctly handled.
175
176 case spv::StorageClassUniformConstant:
177 case spv::StorageClassWorkgroup:
178 case spv::StorageClassCrossWorkgroup:
179 case spv::StorageClassGeneric:
180 case spv::StorageClassPushConstant:
181 case spv::StorageClassAtomicCounter:
182 case spv::StorageClassImage:
183 UNIMPLEMENTED("StorageClass %d not yet implemented", (int)storageClass);
184 break;
185
186 default:
187 UNREACHABLE("Unexpected StorageClass"); // See Appendix A of the Vulkan spec.
188 break;
Chris Forbesc25b8072018-12-10 15:10:39 -0800189 }
Chris Forbes4a979dc2019-01-17 09:36:46 -0800190 break;
191 }
Chris Forbes296aa252018-12-27 11:48:21 -0800192
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800193 case spv::OpConstant:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800194 CreateConstant(insn).constantValue[0] = insn.word(3);
195 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800196 case spv::OpConstantFalse:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800197 CreateConstant(insn).constantValue[0] = 0; // represent boolean false as zero
198 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800199 case spv::OpConstantTrue:
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800200 CreateConstant(insn).constantValue[0] = ~0u; // represent boolean true as all bits set
201 break;
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800202 case spv::OpConstantNull:
203 {
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800204 // OpConstantNull forms a constant of arbitrary type, all zeros.
Ben Clayton9a162482019-02-25 11:54:43 +0000205 auto &object = CreateConstant(insn);
206 auto &objectTy = getType(object.type);
207 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800208 {
209 object.constantValue[i] = 0;
210 }
211 break;
212 }
213 case spv::OpConstantComposite:
214 {
215 auto &object = CreateConstant(insn);
216 auto offset = 0u;
217 for (auto i = 0u; i < insn.wordCount() - 3; i++)
218 {
Ben Clayton9a162482019-02-25 11:54:43 +0000219 auto &constituent = getObject(insn.word(i + 3));
220 auto &constituentTy = getType(constituent.type);
221 for (auto j = 0u; j < constituentTy.sizeInComponents; j++)
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800222 object.constantValue[offset++] = constituent.constantValue[j];
223 }
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800224 break;
225 }
226
Chris Forbesbde34082018-12-28 12:03:10 -0800227 case spv::OpCapability:
228 // Various capabilities will be declared, but none affect our code generation at this point.
229 case spv::OpMemoryModel:
230 // Memory model does not affect our code generation until we decide to do Vulkan Memory Model support.
231 case spv::OpEntryPoint:
Chris Forbes7edf5342019-02-10 22:41:21 +0000232 case spv::OpFunction:
233 case spv::OpFunctionEnd:
234 // Due to preprocessing, the entrypoint and its function provide no value.
235 break;
236 case spv::OpExtInstImport:
237 // We will only support the GLSL 450 extended instruction set, so no point in tracking the ID we assign it.
238 // Valid shaders will not attempt to import any other instruction sets.
Chris Forbes9667a5b2019-03-07 09:26:48 -0800239 if (0 != strcmp("GLSL.std.450", reinterpret_cast<char const *>(insn.wordPointer(2))))
240 {
241 UNIMPLEMENTED("Only GLSL extended instruction set is supported");
242 }
243 break;
Chris Forbes1776af72019-02-22 17:39:57 -0800244 case spv::OpName:
245 case spv::OpMemberName:
246 case spv::OpSource:
247 case spv::OpSourceContinued:
248 case spv::OpSourceExtension:
Chris Forbesf3a430d2019-03-08 07:51:39 -0800249 case spv::OpLine:
250 case spv::OpNoLine:
251 case spv::OpModuleProcessed:
252 case spv::OpString:
Chris Forbes1776af72019-02-22 17:39:57 -0800253 // No semantic impact
Chris Forbes7edf5342019-02-10 22:41:21 +0000254 break;
255
256 case spv::OpFunctionParameter:
257 case spv::OpFunctionCall:
258 case spv::OpSpecConstant:
259 case spv::OpSpecConstantComposite:
260 case spv::OpSpecConstantFalse:
261 case spv::OpSpecConstantOp:
262 case spv::OpSpecConstantTrue:
263 // These should have all been removed by preprocessing passes. If we see them here,
264 // our assumptions are wrong and we will probably generate wrong code.
265 UNIMPLEMENTED("These instructions should have already been lowered.");
266 break;
267
Chris Forbes4d503052019-03-01 17:13:57 -0800268 case spv::OpFConvert:
269 case spv::OpSConvert:
270 case spv::OpUConvert:
271 UNIMPLEMENTED("No valid uses for Op*Convert until we support multiple bit widths");
272 break;
273
Chris Forbesa71b8e92019-02-10 22:42:42 +0000274 case spv::OpLoad:
275 case spv::OpAccessChain:
Chris Forbesb97a9572019-02-21 16:51:42 -0800276 case spv::OpCompositeConstruct:
Chris Forbes1bc1acf2019-02-21 18:40:33 -0800277 case spv::OpCompositeInsert:
Chris Forbesb12846d2019-02-21 18:53:58 -0800278 case spv::OpCompositeExtract:
Chris Forbes83fc5442019-02-26 22:16:07 -0800279 case spv::OpVectorShuffle:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000280 case spv::OpNot: // Unary ops
281 case spv::OpSNegate:
282 case spv::OpFNegate:
283 case spv::OpLogicalNot:
284 case spv::OpIAdd: // Binary ops
285 case spv::OpISub:
286 case spv::OpIMul:
287 case spv::OpSDiv:
288 case spv::OpUDiv:
289 case spv::OpFAdd:
290 case spv::OpFSub:
Chris Forbes9d931532019-03-08 09:53:03 -0800291 case spv::OpFMul:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000292 case spv::OpFDiv:
Ben Claytonec1aeb82019-03-04 19:33:27 +0000293 case spv::OpFOrdEqual:
294 case spv::OpFUnordEqual:
295 case spv::OpFOrdNotEqual:
296 case spv::OpFUnordNotEqual:
297 case spv::OpFOrdLessThan:
298 case spv::OpFUnordLessThan:
299 case spv::OpFOrdGreaterThan:
300 case spv::OpFUnordGreaterThan:
301 case spv::OpFOrdLessThanEqual:
302 case spv::OpFUnordLessThanEqual:
303 case spv::OpFOrdGreaterThanEqual:
304 case spv::OpFUnordGreaterThanEqual:
Ben Claytonbb8c8e22019-03-08 12:04:00 +0000305 case spv::OpSMod:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000306 case spv::OpUMod:
Ben Claytone95eeb12019-03-04 16:32:09 +0000307 case spv::OpIEqual:
308 case spv::OpINotEqual:
309 case spv::OpUGreaterThan:
310 case spv::OpSGreaterThan:
311 case spv::OpUGreaterThanEqual:
312 case spv::OpSGreaterThanEqual:
313 case spv::OpULessThan:
314 case spv::OpSLessThan:
315 case spv::OpULessThanEqual:
316 case spv::OpSLessThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +0000317 case spv::OpShiftRightLogical:
318 case spv::OpShiftRightArithmetic:
319 case spv::OpShiftLeftLogical:
320 case spv::OpBitwiseOr:
321 case spv::OpBitwiseXor:
322 case spv::OpBitwiseAnd:
323 case spv::OpLogicalOr:
324 case spv::OpLogicalAnd:
Chris Forbes787b4462019-03-08 12:16:57 -0800325 case spv::OpLogicalEqual:
326 case spv::OpLogicalNotEqual:
Chris Forbese86b6dc2019-03-01 09:08:47 -0800327 case spv::OpUMulExtended:
328 case spv::OpSMulExtended:
Chris Forbes2b287cc2019-03-01 13:24:17 -0800329 case spv::OpDot:
Chris Forbes4d503052019-03-01 17:13:57 -0800330 case spv::OpConvertFToU:
331 case spv::OpConvertFToS:
332 case spv::OpConvertSToF:
333 case spv::OpConvertUToF:
334 case spv::OpBitcast:
Ben Claytonbf943f62019-03-05 12:57:39 +0000335 case spv::OpSelect:
Chris Forbes9667a5b2019-03-07 09:26:48 -0800336 case spv::OpExtInst:
Chris Forbes3ed33ce2019-03-07 13:38:31 -0800337 case spv::OpIsInf:
338 case spv::OpIsNan:
Chris Forbes0785f692019-03-08 09:09:18 -0800339 case spv::OpAny:
340 case spv::OpAll:
Chris Forbes856ebf82019-03-08 15:30:18 -0800341 case spv::OpVectorTimesScalar:
Chris Forbese86b6dc2019-03-01 09:08:47 -0800342 // Instructions that yield an intermediate value
Chris Forbesa71b8e92019-02-10 22:42:42 +0000343 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000344 TypeID typeId = insn.word(1);
345 ObjectID resultId = insn.word(2);
Chris Forbesa71b8e92019-02-10 22:42:42 +0000346 auto &object = defs[resultId];
Ben Clayton9a162482019-02-25 11:54:43 +0000347 object.type = typeId;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000348 object.kind = Object::Kind::Value;
349 object.definition = insn;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000350
351 if (insn.opcode() == spv::OpAccessChain)
352 {
353 // interior ptr has two parts:
354 // - logical base ptr, common across all lanes and known at compile time
355 // - per-lane offset
Ben Clayton9a162482019-02-25 11:54:43 +0000356 ObjectID baseId = insn.word(3);
357 object.pointerBase = getObject(baseId).pointerBase;
Chris Forbesa71b8e92019-02-10 22:42:42 +0000358 }
359 break;
360 }
361
Chris Forbes7edf5342019-02-10 22:41:21 +0000362 case spv::OpStore:
Chris Forbes7edf5342019-02-10 22:41:21 +0000363 // Don't need to do anything during analysis pass
364 break;
365
366 case spv::OpKill:
367 modes.ContainsKill = true;
Chris Forbesbde34082018-12-28 12:03:10 -0800368 break;
369
Chris Forbes4a979dc2019-01-17 09:36:46 -0800370 default:
Chris Forbese57f10e2019-03-04 10:53:07 -0800371 UNIMPLEMENTED(OpcodeName(insn.opcode()).c_str());
Chris Forbesaf4ed532018-12-06 18:33:27 -0800372 }
373 }
374 }
375
Ben Clayton0bb83b82019-02-26 11:41:07 +0000376 void SpirvShader::DeclareType(InsnIterator insn)
377 {
378 TypeID resultId = insn.word(1);
379
380 auto &type = types[resultId];
381 type.definition = insn;
382 type.sizeInComponents = ComputeTypeSize(insn);
383
384 // A structure is a builtin block if it has a builtin
385 // member. All members of such a structure are builtins.
386 switch (insn.opcode())
387 {
388 case spv::OpTypeStruct:
389 {
390 auto d = memberDecorations.find(resultId);
391 if (d != memberDecorations.end())
392 {
393 for (auto &m : d->second)
394 {
395 if (m.HasBuiltIn)
396 {
397 type.isBuiltInBlock = true;
398 break;
399 }
400 }
401 }
402 break;
403 }
404 case spv::OpTypePointer:
405 {
406 TypeID elementTypeId = insn.word(3);
407 type.element = elementTypeId;
408 type.isBuiltInBlock = getType(elementTypeId).isBuiltInBlock;
409 type.storageClass = static_cast<spv::StorageClass>(insn.word(2));
410 break;
411 }
412 case spv::OpTypeVector:
413 case spv::OpTypeMatrix:
414 case spv::OpTypeArray:
415 case spv::OpTypeRuntimeArray:
416 {
417 TypeID elementTypeId = insn.word(2);
418 type.element = elementTypeId;
419 break;
420 }
421 default:
422 break;
423 }
424 }
425
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800426 SpirvShader::Object& SpirvShader::CreateConstant(InsnIterator insn)
427 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000428 TypeID typeId = insn.word(1);
429 ObjectID resultId = insn.word(2);
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800430 auto &object = defs[resultId];
Ben Clayton9a162482019-02-25 11:54:43 +0000431 auto &objectTy = getType(typeId);
432 object.type = typeId;
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800433 object.kind = Object::Kind::Constant;
434 object.definition = insn;
Ben Clayton9a162482019-02-25 11:54:43 +0000435 object.constantValue = std::unique_ptr<uint32_t[]>(new uint32_t[objectTy.sizeInComponents]);
Chris Forbes1ca8acd2019-02-20 13:00:54 -0800436 return object;
437 }
438
Chris Forbes049ff382019-02-02 15:16:43 -0800439 void SpirvShader::ProcessInterfaceVariable(Object &object)
Chris Forbesbde34082018-12-28 12:03:10 -0800440 {
Ben Clayton9a162482019-02-25 11:54:43 +0000441 auto &objectTy = getType(object.type);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000442 ASSERT(objectTy.storageClass == spv::StorageClassInput || objectTy.storageClass == spv::StorageClassOutput);
Chris Forbesbde34082018-12-28 12:03:10 -0800443
Ben Clayton6fae32c2019-02-28 20:06:42 +0000444 ASSERT(objectTy.definition.opcode() == spv::OpTypePointer);
Ben Clayton9a162482019-02-25 11:54:43 +0000445 auto pointeeTy = getType(objectTy.element);
Chris Forbesbde34082018-12-28 12:03:10 -0800446
Ben Clayton9a162482019-02-25 11:54:43 +0000447 auto &builtinInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
448 auto &userDefinedInterface = (objectTy.storageClass == spv::StorageClassInput) ? inputs : outputs;
449
Ben Clayton6fae32c2019-02-28 20:06:42 +0000450 ASSERT(object.definition.opcode() == spv::OpVariable);
Ben Claytonab51bbf2019-02-20 14:36:27 +0000451 ObjectID resultId = object.definition.word(2);
Ben Clayton9a162482019-02-25 11:54:43 +0000452
453 if (objectTy.isBuiltInBlock)
Chris Forbesbde34082018-12-28 12:03:10 -0800454 {
455 // walk the builtin block, registering each of its members separately.
Ben Clayton9a162482019-02-25 11:54:43 +0000456 auto m = memberDecorations.find(objectTy.element);
Ben Clayton6fae32c2019-02-28 20:06:42 +0000457 ASSERT(m != memberDecorations.end()); // otherwise we wouldn't have marked the type chain
Ben Clayton9a162482019-02-25 11:54:43 +0000458 auto &structType = pointeeTy.definition;
Chris Forbesbde34082018-12-28 12:03:10 -0800459 auto offset = 0u;
460 auto word = 2u;
461 for (auto &member : m->second)
462 {
Chris Forbes840809a2019-01-14 14:30:20 -0800463 auto &memberType = getType(structType.word(word));
Chris Forbesbde34082018-12-28 12:03:10 -0800464
465 if (member.HasBuiltIn)
466 {
467 builtinInterface[member.BuiltIn] = {resultId, offset, memberType.sizeInComponents};
468 }
469
470 offset += memberType.sizeInComponents;
471 ++word;
472 }
473 return;
474 }
475
476 auto d = decorations.find(resultId);
477 if (d != decorations.end() && d->second.HasBuiltIn)
478 {
Ben Clayton9a162482019-02-25 11:54:43 +0000479 builtinInterface[d->second.BuiltIn] = {resultId, 0, pointeeTy.sizeInComponents};
Chris Forbesbde34082018-12-28 12:03:10 -0800480 }
481 else
482 {
Chris Forbes049ff382019-02-02 15:16:43 -0800483 object.kind = Object::Kind::InterfaceVariable;
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800484 VisitInterface(resultId,
485 [&userDefinedInterface](Decorations const &d, AttribType type) {
486 // Populate a single scalar slot in the interface from a collection of decorations and the intended component type.
487 auto scalarSlot = (d.Location << 2) | d.Component;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000488 ASSERT(scalarSlot >= 0 &&
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800489 scalarSlot < static_cast<int32_t>(userDefinedInterface.size()));
490
491 auto &slot = userDefinedInterface[scalarSlot];
492 slot.Type = type;
493 slot.Flat = d.Flat;
494 slot.NoPerspective = d.NoPerspective;
495 slot.Centroid = d.Centroid;
496 });
Chris Forbesbde34082018-12-28 12:03:10 -0800497 }
498 }
499
Chris Forbesaf4ed532018-12-06 18:33:27 -0800500 void SpirvShader::ProcessExecutionMode(InsnIterator insn)
501 {
502 auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
Chris Forbes4a979dc2019-01-17 09:36:46 -0800503 switch (mode)
504 {
505 case spv::ExecutionModeEarlyFragmentTests:
506 modes.EarlyFragmentTests = true;
507 break;
508 case spv::ExecutionModeDepthReplacing:
509 modes.DepthReplacing = true;
510 break;
511 case spv::ExecutionModeDepthGreater:
512 modes.DepthGreater = true;
513 break;
514 case spv::ExecutionModeDepthLess:
515 modes.DepthLess = true;
516 break;
517 case spv::ExecutionModeDepthUnchanged:
518 modes.DepthUnchanged = true;
519 break;
520 case spv::ExecutionModeLocalSize:
521 modes.LocalSizeX = insn.word(3);
522 modes.LocalSizeZ = insn.word(5);
523 modes.LocalSizeY = insn.word(4);
524 break;
525 case spv::ExecutionModeOriginUpperLeft:
526 // This is always the case for a Vulkan shader. Do nothing.
527 break;
528 default:
529 UNIMPLEMENTED("No other execution modes are permitted");
Chris Forbesaf4ed532018-12-06 18:33:27 -0800530 }
531 }
Chris Forbes739a7fb2018-12-08 13:09:40 -0800532
533 uint32_t SpirvShader::ComputeTypeSize(sw::SpirvShader::InsnIterator insn)
534 {
535 // Types are always built from the bottom up (with the exception of forward ptrs, which
536 // don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
537 // already been described (and so their sizes determined)
538 switch (insn.opcode())
539 {
540 case spv::OpTypeVoid:
541 case spv::OpTypeSampler:
542 case spv::OpTypeImage:
543 case spv::OpTypeSampledImage:
544 case spv::OpTypeFunction:
545 case spv::OpTypeRuntimeArray:
546 // Objects that don't consume any space.
547 // Descriptor-backed objects currently only need exist at compile-time.
548 // Runtime arrays don't appear in places where their size would be interesting
549 return 0;
550
551 case spv::OpTypeBool:
552 case spv::OpTypeFloat:
553 case spv::OpTypeInt:
554 // All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
555 // we might need to change this, but only 32 bit components are required for Vulkan 1.1.
556 return 1;
557
558 case spv::OpTypeVector:
559 case spv::OpTypeMatrix:
560 // Vectors and matrices both consume element count * element size.
Chris Forbes840809a2019-01-14 14:30:20 -0800561 return getType(insn.word(2)).sizeInComponents * insn.word(3);
Chris Forbes739a7fb2018-12-08 13:09:40 -0800562
563 case spv::OpTypeArray:
Chris Forbes5be4d702018-12-27 16:12:31 -0800564 {
565 // Element count * element size. Array sizes come from constant ids.
566 auto arraySize = GetConstantInt(insn.word(3));
Chris Forbes840809a2019-01-14 14:30:20 -0800567 return getType(insn.word(2)).sizeInComponents * arraySize;
Chris Forbes5be4d702018-12-27 16:12:31 -0800568 }
Chris Forbes739a7fb2018-12-08 13:09:40 -0800569
570 case spv::OpTypeStruct:
571 {
572 uint32_t size = 0;
573 for (uint32_t i = 2u; i < insn.wordCount(); i++)
574 {
Chris Forbes840809a2019-01-14 14:30:20 -0800575 size += getType(insn.word(i)).sizeInComponents;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800576 }
577 return size;
578 }
579
580 case spv::OpTypePointer:
Chris Forbes0f59a2c2019-02-10 23:03:12 +0000581 // Runtime representation of a pointer is a per-lane index.
582 // Note: clients are expected to look through the pointer if they want the pointee size instead.
583 return 1;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800584
585 default:
586 // Some other random insn.
587 UNIMPLEMENTED("Only types are supported");
Ben Clayton60a3d6f2019-02-26 17:24:46 +0000588 return 0;
Chris Forbes739a7fb2018-12-08 13:09:40 -0800589 }
590 }
Chris Forbesc25b8072018-12-10 15:10:39 -0800591
Ben Clayton831db962019-02-27 14:57:18 +0000592 bool SpirvShader::IsStorageInterleavedByLane(spv::StorageClass storageClass)
593 {
594 switch (storageClass)
595 {
596 case spv::StorageClassUniform:
597 case spv::StorageClassStorageBuffer:
598 return false;
599 default:
600 return true;
601 }
602 }
603
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800604 template<typename F>
Ben Claytonab51bbf2019-02-20 14:36:27 +0000605 int SpirvShader::VisitInterfaceInner(TypeID id, Decorations d, F f) const
Chris Forbes5839dcf2018-12-10 19:02:58 -0800606 {
607 // Recursively walks variable definition and its type tree, taking into account
608 // any explicit Location or Component decorations encountered; where explicit
609 // Locations or Components are not specified, assigns them sequentially.
610 // Collected decorations are carried down toward the leaves and across
611 // siblings; Effect of decorations intentionally does not flow back up the tree.
612 //
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800613 // F is a functor to be called with the effective decoration set for every component.
614 //
615 // Returns the next available location, and calls f().
Chris Forbes5839dcf2018-12-10 19:02:58 -0800616
617 // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
618
Chris Forbes49d664d2019-02-12 19:24:50 +0000619 ApplyDecorationsForId(&d, id);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800620
Chris Forbes840809a2019-01-14 14:30:20 -0800621 auto const &obj = getType(id);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800622 switch (obj.definition.opcode())
623 {
Chris Forbes5839dcf2018-12-10 19:02:58 -0800624 case spv::OpTypePointer:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800625 return VisitInterfaceInner<F>(obj.definition.word(3), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800626 case spv::OpTypeMatrix:
627 for (auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
628 {
629 // consumes same components of N consecutive locations
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800630 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800631 }
632 return d.Location;
633 case spv::OpTypeVector:
634 for (auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
635 {
636 // consumes N consecutive components in the same location
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800637 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800638 }
639 return d.Location + 1;
640 case spv::OpTypeFloat:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800641 f(d, ATTRIBTYPE_FLOAT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800642 return d.Location + 1;
643 case spv::OpTypeInt:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800644 f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800645 return d.Location + 1;
646 case spv::OpTypeBool:
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800647 f(d, ATTRIBTYPE_UINT);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800648 return d.Location + 1;
649 case spv::OpTypeStruct:
650 {
Chris Forbes5839dcf2018-12-10 19:02:58 -0800651 // iterate over members, which may themselves have Location/Component decorations
652 for (auto i = 0u; i < obj.definition.wordCount() - 2; i++)
653 {
Chris Forbes49d664d2019-02-12 19:24:50 +0000654 ApplyDecorationsForIdMember(&d, id, i);
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800655 d.Location = VisitInterfaceInner<F>(obj.definition.word(i + 2), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800656 d.Component = 0; // Implicit locations always have component=0
657 }
658 return d.Location;
659 }
Chris Forbes5be4d702018-12-27 16:12:31 -0800660 case spv::OpTypeArray:
661 {
662 auto arraySize = GetConstantInt(obj.definition.word(3));
663 for (auto i = 0u; i < arraySize; i++)
664 {
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800665 d.Location = VisitInterfaceInner<F>(obj.definition.word(2), d, f);
Chris Forbes5be4d702018-12-27 16:12:31 -0800666 }
667 return d.Location;
668 }
Chris Forbes5839dcf2018-12-10 19:02:58 -0800669 default:
670 // Intentionally partial; most opcodes do not participate in type hierarchies
671 return 0;
672 }
673 }
674
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800675 template<typename F>
Ben Claytonab51bbf2019-02-20 14:36:27 +0000676 void SpirvShader::VisitInterface(ObjectID id, F f) const
Chris Forbes5839dcf2018-12-10 19:02:58 -0800677 {
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800678 // Walk a variable definition and call f for each component in it.
Chris Forbes5839dcf2018-12-10 19:02:58 -0800679 Decorations d{};
Chris Forbes49d664d2019-02-12 19:24:50 +0000680 ApplyDecorationsForId(&d, id);
Chris Forbes1c658232019-02-01 17:12:25 -0800681
682 auto def = getObject(id).definition;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000683 ASSERT(def.opcode() == spv::OpVariable);
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800684 VisitInterfaceInner<F>(def.word(1), d, f);
Chris Forbes5839dcf2018-12-10 19:02:58 -0800685 }
686
Ben Clayton24ea5152019-02-26 11:02:42 +0000687 SIMD::Int SpirvShader::WalkAccessChain(ObjectID id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
Chris Forbes38f85b32019-02-12 20:10:05 +0000688 {
Chris Forbes38f85b32019-02-12 20:10:05 +0000689 // TODO: think about explicit layout (UBO/SSBO) storage classes
690 // TODO: avoid doing per-lane work in some cases if we can?
691
Chris Forbes6397ed02019-02-15 16:39:17 -0800692 int constantOffset = 0;
Ben Clayton24ea5152019-02-26 11:02:42 +0000693 SIMD::Int dynamicOffset = SIMD::Int(0);
Ben Clayton9a162482019-02-25 11:54:43 +0000694 auto &baseObject = getObject(id);
695 TypeID typeId = getType(baseObject.type).element;
Chris Forbes38f85b32019-02-12 20:10:05 +0000696
Chris Forbese4ef5f72019-02-15 16:00:08 -0800697 // The <base> operand is an intermediate value itself, ie produced by a previous OpAccessChain.
698 // Start with its offset and build from there.
Chris Forbes38f85b32019-02-12 20:10:05 +0000699 if (baseObject.kind == Object::Kind::Value)
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000700 {
701 dynamicOffset += routine->getIntermediate(id).Int(0);
702 }
Chris Forbes38f85b32019-02-12 20:10:05 +0000703
704 for (auto i = 0u; i < numIndexes; i++)
705 {
706 auto & type = getType(typeId);
707 switch (type.definition.opcode())
708 {
709 case spv::OpTypeStruct:
710 {
711 int memberIndex = GetConstantInt(indexIds[i]);
712 int offsetIntoStruct = 0;
713 for (auto j = 0; j < memberIndex; j++) {
Chris Forbes58bee562019-02-19 17:41:41 -0800714 auto memberType = type.definition.word(2u + j);
715 offsetIntoStruct += getType(memberType).sizeInComponents;
Chris Forbes38f85b32019-02-12 20:10:05 +0000716 }
Chris Forbes6397ed02019-02-15 16:39:17 -0800717 constantOffset += offsetIntoStruct;
Chris Forbes58bee562019-02-19 17:41:41 -0800718 typeId = type.definition.word(2u + memberIndex);
Chris Forbes38f85b32019-02-12 20:10:05 +0000719 break;
720 }
721
722 case spv::OpTypeVector:
723 case spv::OpTypeMatrix:
724 case spv::OpTypeArray:
Ben Claytonfa8603c2019-03-08 16:51:42 +0000725 case spv::OpTypeRuntimeArray:
Chris Forbes38f85b32019-02-12 20:10:05 +0000726 {
Ben Claytonfa8603c2019-03-08 16:51:42 +0000727 // TODO: b/127950082: Check bounds.
Ben Clayton9a162482019-02-25 11:54:43 +0000728 auto stride = getType(type.element).sizeInComponents;
Chris Forbes38f85b32019-02-12 20:10:05 +0000729 auto & obj = getObject(indexIds[i]);
730 if (obj.kind == Object::Kind::Constant)
Chris Forbes6397ed02019-02-15 16:39:17 -0800731 constantOffset += stride * GetConstantInt(indexIds[i]);
Chris Forbes38f85b32019-02-12 20:10:05 +0000732 else
Ben Clayton9b62c5e2019-03-08 09:32:34 +0000733 dynamicOffset += SIMD::Int(stride) * routine->getIntermediate(indexIds[i]).Int(0);
Ben Clayton9a162482019-02-25 11:54:43 +0000734 typeId = type.element;
Chris Forbes38f85b32019-02-12 20:10:05 +0000735 break;
736 }
737
738 default:
Ben Claytond4e4c662019-02-26 11:54:34 +0000739 UNIMPLEMENTED("Unexpected type '%s' in WalkAccessChain", OpcodeName(type.definition.opcode()).c_str());
Chris Forbes38f85b32019-02-12 20:10:05 +0000740 }
741 }
742
Ben Clayton24ea5152019-02-26 11:02:42 +0000743 return dynamicOffset + SIMD::Int(constantOffset);
Chris Forbes38f85b32019-02-12 20:10:05 +0000744 }
745
Chris Forbes9638b942019-02-21 18:39:31 -0800746 uint32_t SpirvShader::WalkLiteralAccessChain(TypeID typeId, uint32_t numIndexes, uint32_t const *indexes) const
747 {
748 uint32_t constantOffset = 0;
749
750 for (auto i = 0u; i < numIndexes; i++)
751 {
752 auto & type = getType(typeId);
753 switch (type.definition.opcode())
754 {
755 case spv::OpTypeStruct:
756 {
757 int memberIndex = indexes[i];
758 int offsetIntoStruct = 0;
759 for (auto j = 0; j < memberIndex; j++) {
760 auto memberType = type.definition.word(2u + j);
761 offsetIntoStruct += getType(memberType).sizeInComponents;
762 }
763 constantOffset += offsetIntoStruct;
764 typeId = type.definition.word(2u + memberIndex);
765 break;
766 }
767
768 case spv::OpTypeVector:
769 case spv::OpTypeMatrix:
770 case spv::OpTypeArray:
771 {
772 auto elementType = type.definition.word(2);
773 auto stride = getType(elementType).sizeInComponents;
774 constantOffset += stride * indexes[i];
775 typeId = elementType;
776 break;
777 }
778
779 default:
780 UNIMPLEMENTED("Unexpected type in WalkLiteralAccessChain");
781 }
782 }
783
784 return constantOffset;
785 }
786
Chris Forbesc25b8072018-12-10 15:10:39 -0800787 void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
788 {
789 switch (decoration)
790 {
791 case spv::DecorationLocation:
792 HasLocation = true;
793 Location = static_cast<int32_t>(arg);
794 break;
795 case spv::DecorationComponent:
796 HasComponent = true;
797 Component = arg;
798 break;
Ben Claytond073d8e2019-02-26 11:06:50 +0000799 case spv::DecorationDescriptorSet:
800 HasDescriptorSet = true;
801 DescriptorSet = arg;
802 break;
803 case spv::DecorationBinding:
804 HasBinding = true;
805 Binding = arg;
806 break;
Chris Forbesc25b8072018-12-10 15:10:39 -0800807 case spv::DecorationBuiltIn:
808 HasBuiltIn = true;
809 BuiltIn = static_cast<spv::BuiltIn>(arg);
810 break;
811 case spv::DecorationFlat:
812 Flat = true;
813 break;
814 case spv::DecorationNoPerspective:
Chris Forbes5839dcf2018-12-10 19:02:58 -0800815 NoPerspective = true;
Chris Forbesc25b8072018-12-10 15:10:39 -0800816 break;
817 case spv::DecorationCentroid:
818 Centroid = true;
819 break;
820 case spv::DecorationBlock:
821 Block = true;
822 break;
823 case spv::DecorationBufferBlock:
824 BufferBlock = true;
825 break;
Chris Forbes65321072019-03-07 16:13:56 -0800826 case spv::DecorationOffset:
827 HasOffset = true;
828 Offset = static_cast<int32_t>(arg);
829 break;
830 case spv::DecorationArrayStride:
831 HasArrayStride = true;
832 ArrayStride = static_cast<int32_t>(arg);
833 break;
834 case spv::DecorationMatrixStride:
835 HasMatrixStride = true;
836 MatrixStride = static_cast<int32_t>(arg);
837 break;
Chris Forbesc25b8072018-12-10 15:10:39 -0800838 default:
839 // Intentionally partial, there are many decorations we just don't care about.
840 break;
841 }
842 }
843
844 void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src)
845 {
846 // Apply a decoration group to this set of decorations
847 if (src.HasBuiltIn)
848 {
849 HasBuiltIn = true;
850 BuiltIn = src.BuiltIn;
851 }
852
853 if (src.HasLocation)
854 {
855 HasLocation = true;
856 Location = src.Location;
857 }
858
859 if (src.HasComponent)
860 {
861 HasComponent = true;
862 Component = src.Component;
863 }
864
Ben Claytond073d8e2019-02-26 11:06:50 +0000865 if (src.HasDescriptorSet)
866 {
867 HasDescriptorSet = true;
868 DescriptorSet = src.DescriptorSet;
869 }
870
871 if (src.HasBinding)
872 {
873 HasBinding = true;
874 Binding = src.Binding;
875 }
876
Chris Forbes65321072019-03-07 16:13:56 -0800877 if (src.HasOffset)
878 {
879 HasOffset = true;
880 Offset = src.Offset;
881 }
882
883 if (src.HasArrayStride)
884 {
885 HasArrayStride = true;
886 ArrayStride = src.ArrayStride;
887 }
888
889 if (src.HasMatrixStride)
890 {
891 HasMatrixStride = true;
892 MatrixStride = src.MatrixStride;
893 }
894
Chris Forbesc25b8072018-12-10 15:10:39 -0800895 Flat |= src.Flat;
Chris Forbes5839dcf2018-12-10 19:02:58 -0800896 NoPerspective |= src.NoPerspective;
Chris Forbesc25b8072018-12-10 15:10:39 -0800897 Centroid |= src.Centroid;
898 Block |= src.Block;
899 BufferBlock |= src.BufferBlock;
900 }
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800901
Ben Claytonab51bbf2019-02-20 14:36:27 +0000902 void SpirvShader::ApplyDecorationsForId(Decorations *d, TypeOrObjectID id) const
Chris Forbes49d664d2019-02-12 19:24:50 +0000903 {
904 auto it = decorations.find(id);
905 if (it != decorations.end())
906 d->Apply(it->second);
907 }
908
Ben Claytonab51bbf2019-02-20 14:36:27 +0000909 void SpirvShader::ApplyDecorationsForIdMember(Decorations *d, TypeID id, uint32_t member) const
Chris Forbes49d664d2019-02-12 19:24:50 +0000910 {
911 auto it = memberDecorations.find(id);
912 if (it != memberDecorations.end() && member < it->second.size())
913 {
914 d->Apply(it->second[member]);
915 }
916 }
917
Ben Claytonab51bbf2019-02-20 14:36:27 +0000918 uint32_t SpirvShader::GetConstantInt(ObjectID id) const
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800919 {
920 // Slightly hackish access to constants very early in translation.
921 // General consumption of constants by other instructions should
922 // probably be just lowered to Reactor.
923
924 // TODO: not encountered yet since we only use this for array sizes etc,
925 // but is possible to construct integer constant 0 via OpConstantNull.
Chris Forbesb8fb08a2019-02-13 11:45:27 -0800926 auto insn = getObject(id).definition;
Ben Clayton6fae32c2019-02-28 20:06:42 +0000927 ASSERT(insn.opcode() == spv::OpConstant);
928 ASSERT(getType(insn.word(1)).definition.opcode() == spv::OpTypeInt);
Chris Forbesbc3a0ee2018-12-27 16:02:58 -0800929 return insn.word(3);
930 }
Chris Forbesd5aed492019-02-02 15:18:52 -0800931
932 // emit-time
933
Chris Forbesc61271e2019-02-19 17:01:28 -0800934 void SpirvShader::emitProlog(SpirvRoutine *routine) const
Chris Forbesd5aed492019-02-02 15:18:52 -0800935 {
936 for (auto insn : *this)
937 {
938 switch (insn.opcode())
939 {
940 case spv::OpVariable:
941 {
Ben Claytonab51bbf2019-02-20 14:36:27 +0000942 ObjectID resultId = insn.word(2);
Chris Forbes0eba65b2019-02-13 12:24:35 -0800943 auto &object = getObject(resultId);
Ben Clayton9a162482019-02-25 11:54:43 +0000944 auto &objectTy = getType(object.type);
945 auto &pointeeTy = getType(objectTy.element);
Chris Forbesd5aed492019-02-02 15:18:52 -0800946 // TODO: what to do about zero-slot objects?
Ben Clayton9a162482019-02-25 11:54:43 +0000947 if (pointeeTy.sizeInComponents > 0)
Chris Forbesd5aed492019-02-02 15:18:52 -0800948 {
Ben Claytonbb8c8e22019-03-08 12:04:00 +0000949 routine->createLvalue(resultId, pointeeTy.sizeInComponents);
Chris Forbesd5aed492019-02-02 15:18:52 -0800950 }
951 break;
952 }
953 default:
Chris Forbese9f8f5b2019-02-11 00:20:16 +0000954 // Nothing else produces interface variables, so can all be safely ignored.
Chris Forbesd5aed492019-02-02 15:18:52 -0800955 break;
956 }
957 }
958 }
959
960 void SpirvShader::emit(SpirvRoutine *routine) const
961 {
Chris Forbesd5aed492019-02-02 15:18:52 -0800962 for (auto insn : *this)
963 {
964 switch (insn.opcode())
965 {
Chris Forbese53533d2019-02-21 16:49:51 -0800966 case spv::OpTypeVoid:
967 case spv::OpTypeInt:
968 case spv::OpTypeFloat:
969 case spv::OpTypeBool:
970 case spv::OpTypeVector:
971 case spv::OpTypeArray:
972 case spv::OpTypeRuntimeArray:
973 case spv::OpTypeMatrix:
974 case spv::OpTypeStruct:
975 case spv::OpTypePointer:
976 case spv::OpTypeFunction:
977 case spv::OpExecutionMode:
978 case spv::OpMemoryModel:
979 case spv::OpFunction:
980 case spv::OpFunctionEnd:
981 case spv::OpConstant:
982 case spv::OpConstantNull:
983 case spv::OpConstantTrue:
984 case spv::OpConstantFalse:
985 case spv::OpConstantComposite:
986 case spv::OpExtension:
987 case spv::OpCapability:
988 case spv::OpEntryPoint:
989 case spv::OpExtInstImport:
990 case spv::OpDecorate:
991 case spv::OpMemberDecorate:
992 case spv::OpGroupDecorate:
993 case spv::OpGroupMemberDecorate:
994 case spv::OpDecorationGroup:
Chris Forbes1776af72019-02-22 17:39:57 -0800995 case spv::OpName:
996 case spv::OpMemberName:
997 case spv::OpSource:
998 case spv::OpSourceContinued:
999 case spv::OpSourceExtension:
Chris Forbesf3a430d2019-03-08 07:51:39 -08001000 case spv::OpLine:
1001 case spv::OpNoLine:
1002 case spv::OpModuleProcessed:
1003 case spv::OpString:
Chris Forbese53533d2019-02-21 16:49:51 -08001004 // Nothing to do at emit time. These are either fully handled at analysis time,
1005 // or don't require any work at all.
1006 break;
1007
Chris Forbese57f10e2019-03-04 10:53:07 -08001008 case spv::OpLabel:
1009 case spv::OpReturn:
1010 // TODO: when we do control flow, will need to do some work here.
1011 // Until then, there is nothing to do -- we expect there to be an initial OpLabel
1012 // in the entrypoint function, for which we do nothing; and a final OpReturn at the
1013 // end of the entrypoint function, for which we do nothing.
1014 break;
1015
Chris Forbes0eba65b2019-02-13 12:24:35 -08001016 case spv::OpVariable:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001017 EmitVariable(insn, routine);
Chris Forbes0eba65b2019-02-13 12:24:35 -08001018 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001019
Chris Forbese9f8f5b2019-02-11 00:20:16 +00001020 case spv::OpLoad:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001021 EmitLoad(insn, routine);
Chris Forbese9f8f5b2019-02-11 00:20:16 +00001022 break;
Chris Forbes38f85b32019-02-12 20:10:05 +00001023
Chris Forbes1c588002019-02-12 18:56:38 +00001024 case spv::OpStore:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001025 EmitStore(insn, routine);
Chris Forbes1c588002019-02-12 18:56:38 +00001026 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001027
1028 case spv::OpAccessChain:
1029 EmitAccessChain(insn, routine);
1030 break;
1031
Chris Forbesb97a9572019-02-21 16:51:42 -08001032 case spv::OpCompositeConstruct:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001033 EmitCompositeConstruct(insn, routine);
Chris Forbesb97a9572019-02-21 16:51:42 -08001034 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001035
Chris Forbes1bc1acf2019-02-21 18:40:33 -08001036 case spv::OpCompositeInsert:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001037 EmitCompositeInsert(insn, routine);
Chris Forbes1bc1acf2019-02-21 18:40:33 -08001038 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001039
Chris Forbesb12846d2019-02-21 18:53:58 -08001040 case spv::OpCompositeExtract:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001041 EmitCompositeExtract(insn, routine);
Chris Forbesb12846d2019-02-21 18:53:58 -08001042 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001043
Chris Forbes83fc5442019-02-26 22:16:07 -08001044 case spv::OpVectorShuffle:
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001045 EmitVectorShuffle(insn, routine);
Chris Forbes83fc5442019-02-26 22:16:07 -08001046 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001047
Chris Forbes856ebf82019-03-08 15:30:18 -08001048 case spv::OpVectorTimesScalar:
1049 EmitVectorTimesScalar(insn, routine);
1050 break;
1051
Ben Claytondd1e37e2019-02-28 19:59:15 +00001052 case spv::OpNot:
1053 case spv::OpSNegate:
1054 case spv::OpFNegate:
1055 case spv::OpLogicalNot:
Chris Forbes4d503052019-03-01 17:13:57 -08001056 case spv::OpConvertFToU:
1057 case spv::OpConvertFToS:
1058 case spv::OpConvertSToF:
1059 case spv::OpConvertUToF:
1060 case spv::OpBitcast:
Chris Forbes3ed33ce2019-03-07 13:38:31 -08001061 case spv::OpIsInf:
1062 case spv::OpIsNan:
Ben Claytondd1e37e2019-02-28 19:59:15 +00001063 EmitUnaryOp(insn, routine);
1064 break;
1065
1066 case spv::OpIAdd:
1067 case spv::OpISub:
1068 case spv::OpIMul:
1069 case spv::OpSDiv:
1070 case spv::OpUDiv:
1071 case spv::OpFAdd:
1072 case spv::OpFSub:
Chris Forbes9d931532019-03-08 09:53:03 -08001073 case spv::OpFMul:
Ben Claytondd1e37e2019-02-28 19:59:15 +00001074 case spv::OpFDiv:
Ben Claytonec1aeb82019-03-04 19:33:27 +00001075 case spv::OpFOrdEqual:
1076 case spv::OpFUnordEqual:
1077 case spv::OpFOrdNotEqual:
1078 case spv::OpFUnordNotEqual:
1079 case spv::OpFOrdLessThan:
1080 case spv::OpFUnordLessThan:
1081 case spv::OpFOrdGreaterThan:
1082 case spv::OpFUnordGreaterThan:
1083 case spv::OpFOrdLessThanEqual:
1084 case spv::OpFUnordLessThanEqual:
1085 case spv::OpFOrdGreaterThanEqual:
1086 case spv::OpFUnordGreaterThanEqual:
Ben Claytonbb8c8e22019-03-08 12:04:00 +00001087 case spv::OpSMod:
Ben Claytondd1e37e2019-02-28 19:59:15 +00001088 case spv::OpUMod:
Ben Claytone95eeb12019-03-04 16:32:09 +00001089 case spv::OpIEqual:
1090 case spv::OpINotEqual:
1091 case spv::OpUGreaterThan:
1092 case spv::OpSGreaterThan:
1093 case spv::OpUGreaterThanEqual:
1094 case spv::OpSGreaterThanEqual:
1095 case spv::OpULessThan:
1096 case spv::OpSLessThan:
1097 case spv::OpULessThanEqual:
1098 case spv::OpSLessThanEqual:
Ben Claytondd1e37e2019-02-28 19:59:15 +00001099 case spv::OpShiftRightLogical:
1100 case spv::OpShiftRightArithmetic:
1101 case spv::OpShiftLeftLogical:
1102 case spv::OpBitwiseOr:
1103 case spv::OpBitwiseXor:
1104 case spv::OpBitwiseAnd:
1105 case spv::OpLogicalOr:
1106 case spv::OpLogicalAnd:
Chris Forbes787b4462019-03-08 12:16:57 -08001107 case spv::OpLogicalEqual:
1108 case spv::OpLogicalNotEqual:
Chris Forbese86b6dc2019-03-01 09:08:47 -08001109 case spv::OpUMulExtended:
1110 case spv::OpSMulExtended:
Ben Claytondd1e37e2019-02-28 19:59:15 +00001111 EmitBinaryOp(insn, routine);
1112 break;
1113
Chris Forbes2b287cc2019-03-01 13:24:17 -08001114 case spv::OpDot:
1115 EmitDot(insn, routine);
1116 break;
1117
Ben Claytonbf943f62019-03-05 12:57:39 +00001118 case spv::OpSelect:
1119 EmitSelect(insn, routine);
1120 break;
1121
Chris Forbes9667a5b2019-03-07 09:26:48 -08001122 case spv::OpExtInst:
1123 EmitExtendedInstruction(insn, routine);
1124 break;
1125
Chris Forbes0785f692019-03-08 09:09:18 -08001126 case spv::OpAny:
1127 EmitAny(insn, routine);
1128 break;
1129
1130 case spv::OpAll:
1131 EmitAll(insn, routine);
1132 break;
1133
Chris Forbesd5aed492019-02-02 15:18:52 -08001134 default:
Chris Forbese57f10e2019-03-04 10:53:07 -08001135 UNIMPLEMENTED(OpcodeName(insn.opcode()).c_str());
Chris Forbesd5aed492019-02-02 15:18:52 -08001136 break;
1137 }
1138 }
1139 }
Chris Forbesc61271e2019-02-19 17:01:28 -08001140
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001141 void SpirvShader::EmitVariable(InsnIterator insn, SpirvRoutine *routine) const
1142 {
1143 ObjectID resultId = insn.word(2);
1144 auto &object = getObject(resultId);
1145 auto &objectTy = getType(object.type);
Ben Claytonefec1b92019-03-05 17:38:16 +00001146 switch (objectTy.storageClass)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001147 {
Ben Claytonefec1b92019-03-05 17:38:16 +00001148 case spv::StorageClassInput:
1149 {
1150 if (object.kind == Object::Kind::InterfaceVariable)
1151 {
1152 auto &dst = routine->getValue(resultId);
1153 int offset = 0;
1154 VisitInterface(resultId,
1155 [&](Decorations const &d, AttribType type) {
1156 auto scalarSlot = d.Location << 2 | d.Component;
1157 dst[offset++] = routine->inputs[scalarSlot];
1158 });
1159 }
1160 break;
1161 }
1162 case spv::StorageClassUniform:
1163 case spv::StorageClassStorageBuffer:
1164 {
1165 Decorations d{};
1166 ApplyDecorationsForId(&d, resultId);
1167 ASSERT(d.DescriptorSet >= 0);
1168 ASSERT(d.Binding >= 0);
1169
1170 size_t bindingOffset = routine->pipelineLayout->getBindingOffset(d.DescriptorSet, d.Binding);
1171
1172 Pointer<Byte> set = routine->descriptorSets[d.DescriptorSet]; // DescriptorSet*
1173 Pointer<Byte> binding = Pointer<Byte>(set + bindingOffset); // VkDescriptorBufferInfo*
1174 Pointer<Byte> buffer = *Pointer<Pointer<Byte>>(binding + OFFSET(VkDescriptorBufferInfo, buffer)); // vk::Buffer*
1175 Pointer<Byte> data = *Pointer<Pointer<Byte>>(buffer + vk::Buffer::DataOffset); // void*
1176 Int offset = *Pointer<Int>(binding + OFFSET(VkDescriptorBufferInfo, offset));
1177 Pointer<Byte> address = data + offset;
1178 routine->physicalPointers[resultId] = address;
1179 break;
1180 }
1181 default:
1182 break;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001183 }
1184 }
1185
1186 void SpirvShader::EmitLoad(InsnIterator insn, SpirvRoutine *routine) const
1187 {
1188 ObjectID objectId = insn.word(2);
1189 ObjectID pointerId = insn.word(3);
1190 auto &object = getObject(objectId);
1191 auto &objectTy = getType(object.type);
1192 auto &pointer = getObject(pointerId);
1193 auto &pointerBase = getObject(pointer.pointerBase);
1194 auto &pointerBaseTy = getType(pointerBase.type);
1195
1196 ASSERT(getType(pointer.type).element == object.type);
1197 ASSERT(TypeID(insn.word(1)) == object.type);
1198
Ben Claytonefec1b92019-03-05 17:38:16 +00001199 if (pointerBaseTy.storageClass == spv::StorageClassImage)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001200 {
Ben Claytonefec1b92019-03-05 17:38:16 +00001201 UNIMPLEMENTED("StorageClassImage load not yet implemented");
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001202 }
1203
Ben Clayton831db962019-02-27 14:57:18 +00001204 Pointer<Float> ptrBase;
1205 if (pointerBase.kind == Object::Kind::PhysicalPointer)
1206 {
1207 ptrBase = routine->getPhysicalPointer(pointer.pointerBase);
1208 }
1209 else
1210 {
1211 ptrBase = &routine->getValue(pointer.pointerBase)[0];
1212 }
1213
1214 bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
1215
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001216 auto &dst = routine->createIntermediate(objectId, objectTy.sizeInComponents);
1217
1218 if (pointer.kind == Object::Kind::Value)
1219 {
Ben Clayton831db962019-02-27 14:57:18 +00001220 // Divergent offsets.
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001221 auto offsets = routine->getIntermediate(pointerId).Int(0);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001222 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
1223 {
1224 // i wish i had a Float,Float,Float,Float constructor here..
1225 SIMD::Float v;
1226 for (int j = 0; j < SIMD::Width; j++)
1227 {
1228 Int offset = Int(i) + Extract(offsets, j);
Ben Clayton831db962019-02-27 14:57:18 +00001229 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
1230 v = Insert(v, ptrBase[offset], j);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001231 }
1232 dst.emplace(i, v);
1233 }
1234 }
Ben Clayton831db962019-02-27 14:57:18 +00001235 else if (interleavedByLane)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001236 {
Ben Clayton831db962019-02-27 14:57:18 +00001237 // Lane-interleaved data. No divergent offsets.
1238 Pointer<SIMD::Float> src = ptrBase;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001239 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
1240 {
Ben Clayton831db962019-02-27 14:57:18 +00001241 dst.emplace(i, src[i]);
1242 }
1243 }
1244 else
1245 {
1246 // Non-interleaved data. No divergent offsets.
1247 for (auto i = 0u; i < objectTy.sizeInComponents; i++)
1248 {
1249 dst.emplace(i, RValue<SIMD::Float>(ptrBase[i]));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001250 }
1251 }
1252 }
1253
1254 void SpirvShader::EmitAccessChain(InsnIterator insn, SpirvRoutine *routine) const
1255 {
1256 TypeID typeId = insn.word(1);
1257 ObjectID objectId = insn.word(2);
1258 ObjectID baseId = insn.word(3);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001259 auto &type = getType(typeId);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001260 ASSERT(type.sizeInComponents == 1);
Ben Clayton03aee542019-03-08 09:45:25 +00001261 ASSERT(getObject(baseId).pointerBase == getObject(objectId).pointerBase);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001262
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001263 auto &dst = routine->createIntermediate(objectId, type.sizeInComponents);
Ben Clayton093be462019-03-08 08:37:24 +00001264 dst.emplace(0, WalkAccessChain(baseId, insn.wordCount() - 4, insn.wordPointer(4), routine));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001265 }
1266
1267 void SpirvShader::EmitStore(InsnIterator insn, SpirvRoutine *routine) const
1268 {
1269 ObjectID pointerId = insn.word(1);
1270 ObjectID objectId = insn.word(2);
1271 auto &object = getObject(objectId);
1272 auto &pointer = getObject(pointerId);
1273 auto &pointerTy = getType(pointer.type);
1274 auto &elementTy = getType(pointerTy.element);
1275 auto &pointerBase = getObject(pointer.pointerBase);
1276 auto &pointerBaseTy = getType(pointerBase.type);
1277
Ben Claytonefec1b92019-03-05 17:38:16 +00001278 if (pointerBaseTy.storageClass == spv::StorageClassImage)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001279 {
Ben Claytonefec1b92019-03-05 17:38:16 +00001280 UNIMPLEMENTED("StorageClassImage store not yet implemented");
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001281 }
1282
Ben Clayton831db962019-02-27 14:57:18 +00001283 Pointer<Float> ptrBase;
1284 if (pointerBase.kind == Object::Kind::PhysicalPointer)
1285 {
1286 ptrBase = routine->getPhysicalPointer(pointer.pointerBase);
1287 }
1288 else
1289 {
1290 ptrBase = &routine->getValue(pointer.pointerBase)[0];
1291 }
1292
1293 bool interleavedByLane = IsStorageInterleavedByLane(pointerBaseTy.storageClass);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001294
1295 if (object.kind == Object::Kind::Constant)
1296 {
1297 auto src = reinterpret_cast<float *>(object.constantValue.get());
1298
1299 if (pointer.kind == Object::Kind::Value)
1300 {
Ben Clayton831db962019-02-27 14:57:18 +00001301 // Constant source data. Divergent offsets.
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001302 auto offsets = routine->getIntermediate(pointerId).Int(0);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001303 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1304 {
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001305 for (int j = 0; j < SIMD::Width; j++)
1306 {
Ben Clayton831db962019-02-27 14:57:18 +00001307 Int offset = Int(i) + Extract(offsets, j);
1308 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
1309 ptrBase[offset] = RValue<Float>(src[i]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001310 }
1311 }
1312 }
1313 else
1314 {
Ben Clayton831db962019-02-27 14:57:18 +00001315 // Constant source data. No divergent offsets.
1316 Pointer<SIMD::Float> dst = ptrBase;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001317 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1318 {
Ben Clayton831db962019-02-27 14:57:18 +00001319 dst[i] = RValue<SIMD::Float>(src[i]);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001320 }
1321 }
1322 }
1323 else
1324 {
1325 auto &src = routine->getIntermediate(objectId);
1326
1327 if (pointer.kind == Object::Kind::Value)
1328 {
Ben Clayton831db962019-02-27 14:57:18 +00001329 // Intermediate source data. Divergent offsets.
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001330 auto offsets = routine->getIntermediate(pointerId).Int(0);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001331 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1332 {
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001333 for (int j = 0; j < SIMD::Width; j++)
1334 {
Ben Clayton831db962019-02-27 14:57:18 +00001335 Int offset = Int(i) + Extract(offsets, j);
1336 if (interleavedByLane) { offset = offset * SIMD::Width + j; }
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001337 ptrBase[offset] = Extract(src.Float(i), j);
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001338 }
1339 }
1340 }
Ben Clayton831db962019-02-27 14:57:18 +00001341 else if (interleavedByLane)
1342 {
1343 // Intermediate source data. Lane-interleaved data. No divergent offsets.
1344 Pointer<SIMD::Float> dst = ptrBase;
1345 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1346 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001347 dst[i] = src.Float(i);
Ben Clayton831db962019-02-27 14:57:18 +00001348 }
1349 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001350 else
1351 {
Ben Clayton831db962019-02-27 14:57:18 +00001352 // Intermediate source data. Non-interleaved data. No divergent offsets.
1353 Pointer<SIMD::Float> dst = ptrBase;
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001354 for (auto i = 0u; i < elementTy.sizeInComponents; i++)
1355 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001356 dst[i] = SIMD::Float(src.Float(i));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001357 }
1358 }
1359 }
1360 }
1361
1362 void SpirvShader::EmitCompositeConstruct(InsnIterator insn, SpirvRoutine *routine) const
1363 {
1364 auto &type = getType(insn.word(1));
1365 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1366 auto offset = 0u;
1367
1368 for (auto i = 0u; i < insn.wordCount() - 3; i++)
1369 {
1370 ObjectID srcObjectId = insn.word(3u + i);
1371 auto & srcObject = getObject(srcObjectId);
1372 auto & srcObjectTy = getType(srcObject.type);
1373 GenericValue srcObjectAccess(this, routine, srcObjectId);
1374
1375 for (auto j = 0u; j < srcObjectTy.sizeInComponents; j++)
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001376 {
1377 dst.emplace(offset++, srcObjectAccess.Float(j));
1378 }
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001379 }
1380 }
1381
1382 void SpirvShader::EmitCompositeInsert(InsnIterator insn, SpirvRoutine *routine) const
1383 {
1384 TypeID resultTypeId = insn.word(1);
1385 auto &type = getType(resultTypeId);
1386 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1387 auto &newPartObject = getObject(insn.word(3));
1388 auto &newPartObjectTy = getType(newPartObject.type);
1389 auto firstNewComponent = WalkLiteralAccessChain(resultTypeId, insn.wordCount() - 5, insn.wordPointer(5));
1390
1391 GenericValue srcObjectAccess(this, routine, insn.word(4));
1392 GenericValue newPartObjectAccess(this, routine, insn.word(3));
1393
1394 // old components before
1395 for (auto i = 0u; i < firstNewComponent; i++)
1396 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001397 dst.emplace(i, srcObjectAccess.Float(i));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001398 }
1399 // new part
1400 for (auto i = 0u; i < newPartObjectTy.sizeInComponents; i++)
1401 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001402 dst.emplace(firstNewComponent + i, newPartObjectAccess.Float(i));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001403 }
1404 // old components after
1405 for (auto i = firstNewComponent + newPartObjectTy.sizeInComponents; i < type.sizeInComponents; i++)
1406 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001407 dst.emplace(i, srcObjectAccess.Float(i));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001408 }
1409 }
1410
1411 void SpirvShader::EmitCompositeExtract(InsnIterator insn, SpirvRoutine *routine) const
1412 {
1413 auto &type = getType(insn.word(1));
1414 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1415 auto &compositeObject = getObject(insn.word(3));
1416 TypeID compositeTypeId = compositeObject.definition.word(1);
1417 auto firstComponent = WalkLiteralAccessChain(compositeTypeId, insn.wordCount() - 4, insn.wordPointer(4));
1418
1419 GenericValue compositeObjectAccess(this, routine, insn.word(3));
1420 for (auto i = 0u; i < type.sizeInComponents; i++)
1421 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001422 dst.emplace(i, compositeObjectAccess.Float(firstComponent + i));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001423 }
1424 }
1425
1426 void SpirvShader::EmitVectorShuffle(InsnIterator insn, SpirvRoutine *routine) const
1427 {
1428 auto &type = getType(insn.word(1));
1429 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1430
Chris Forbes13eba6c2019-03-08 10:41:05 -08001431 // Note: number of components in result type, first half type, and second
1432 // half type are all independent.
1433 auto &firstHalfType = getType(getObject(insn.word(3)).type);
1434
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001435 GenericValue firstHalfAccess(this, routine, insn.word(3));
1436 GenericValue secondHalfAccess(this, routine, insn.word(4));
1437
1438 for (auto i = 0u; i < type.sizeInComponents; i++)
1439 {
1440 auto selector = insn.word(5 + i);
1441 if (selector == static_cast<uint32_t>(-1))
1442 {
1443 // Undefined value. Until we decide to do real undef values, zero is as good
1444 // a value as any
1445 dst.emplace(i, RValue<SIMD::Float>(0.0f));
1446 }
Chris Forbes13eba6c2019-03-08 10:41:05 -08001447 else if (selector < firstHalfType.sizeInComponents)
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001448 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001449 dst.emplace(i, firstHalfAccess.Float(selector));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001450 }
1451 else
1452 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001453 dst.emplace(i, secondHalfAccess.Float(selector - firstHalfType.sizeInComponents));
Ben Claytondfc0f3b2019-02-26 12:19:48 +00001454 }
1455 }
1456 }
1457
Chris Forbes856ebf82019-03-08 15:30:18 -08001458 void SpirvShader::EmitVectorTimesScalar(InsnIterator insn, SpirvRoutine *routine) const
1459 {
1460 auto &type = getType(insn.word(1));
1461 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001462 auto lhs = GenericValue(this, routine, insn.word(3));
1463 auto rhs = GenericValue(this, routine, insn.word(4));
Chris Forbes856ebf82019-03-08 15:30:18 -08001464
1465 for (auto i = 0u; i < type.sizeInComponents; i++)
1466 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001467 dst.emplace(i, lhs.Float(i) * rhs.Float(0));
Chris Forbes856ebf82019-03-08 15:30:18 -08001468 }
1469 }
1470
Ben Claytondd1e37e2019-02-28 19:59:15 +00001471 void SpirvShader::EmitUnaryOp(InsnIterator insn, SpirvRoutine *routine) const
1472 {
1473 auto &type = getType(insn.word(1));
1474 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1475 auto src = GenericValue(this, routine, insn.word(3));
1476
1477 for (auto i = 0u; i < type.sizeInComponents; i++)
1478 {
Ben Claytondd1e37e2019-02-28 19:59:15 +00001479 switch (insn.opcode())
1480 {
1481 case spv::OpNot:
1482 case spv::OpLogicalNot: // logical not == bitwise not due to all-bits boolean representation
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001483 dst.emplace(i, ~src.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001484 break;
1485 case spv::OpSNegate:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001486 dst.emplace(i, -src.Int(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001487 break;
1488 case spv::OpFNegate:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001489 dst.emplace(i, -src.Float(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001490 break;
Chris Forbes4d503052019-03-01 17:13:57 -08001491 case spv::OpConvertFToU:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001492 dst.emplace(i, SIMD::UInt(src.Float(i)));
Chris Forbes4d503052019-03-01 17:13:57 -08001493 break;
1494 case spv::OpConvertFToS:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001495 dst.emplace(i, SIMD::Int(src.Float(i)));
Chris Forbes4d503052019-03-01 17:13:57 -08001496 break;
1497 case spv::OpConvertSToF:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001498 dst.emplace(i, SIMD::Float(src.Int(i)));
Chris Forbes4d503052019-03-01 17:13:57 -08001499 break;
1500 case spv::OpConvertUToF:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001501 dst.emplace(i, SIMD::Float(src.UInt(i)));
Chris Forbes4d503052019-03-01 17:13:57 -08001502 break;
1503 case spv::OpBitcast:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001504 dst.emplace(i, src.Float(i));
Chris Forbes4d503052019-03-01 17:13:57 -08001505 break;
Chris Forbes3ed33ce2019-03-07 13:38:31 -08001506 case spv::OpIsInf:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001507 dst.emplace(i, IsInf(src.Float(i)));
Chris Forbes3ed33ce2019-03-07 13:38:31 -08001508 break;
1509 case spv::OpIsNan:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001510 dst.emplace(i, IsNan(src.Float(i)));
Chris Forbes3ed33ce2019-03-07 13:38:31 -08001511 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001512 default:
1513 UNIMPLEMENTED("Unhandled unary operator %s", OpcodeName(insn.opcode()).c_str());
1514 }
1515 }
1516 }
1517
1518 void SpirvShader::EmitBinaryOp(InsnIterator insn, SpirvRoutine *routine) const
1519 {
1520 auto &type = getType(insn.word(1));
1521 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
Chris Forbese86b6dc2019-03-01 09:08:47 -08001522 auto &lhsType = getType(getObject(insn.word(3)).type);
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001523 auto lhs = GenericValue(this, routine, insn.word(3));
1524 auto rhs = GenericValue(this, routine, insn.word(4));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001525
Chris Forbese86b6dc2019-03-01 09:08:47 -08001526 for (auto i = 0u; i < lhsType.sizeInComponents; i++)
Ben Claytondd1e37e2019-02-28 19:59:15 +00001527 {
Ben Claytondd1e37e2019-02-28 19:59:15 +00001528 switch (insn.opcode())
1529 {
1530 case spv::OpIAdd:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001531 dst.emplace(i, lhs.Int(i) + rhs.Int(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001532 break;
1533 case spv::OpISub:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001534 dst.emplace(i, lhs.Int(i) - rhs.Int(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001535 break;
1536 case spv::OpIMul:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001537 dst.emplace(i, lhs.Int(i) * rhs.Int(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001538 break;
1539 case spv::OpSDiv:
Ben Clayton49d2c132019-03-14 12:21:53 +00001540 {
1541 auto zeroMask = CmpEQ(rhs.Int(i), SIMD::Int(0));
1542 dst.emplace(i, lhs.Int(i) / (rhs.Int(i) | zeroMask));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001543 break;
Ben Clayton49d2c132019-03-14 12:21:53 +00001544 }
Ben Claytondd1e37e2019-02-28 19:59:15 +00001545 case spv::OpUDiv:
Ben Clayton49d2c132019-03-14 12:21:53 +00001546 {
1547 auto zeroMask = As<SIMD::UInt>(CmpEQ(rhs.Int(i), SIMD::Int(0)));
1548 dst.emplace(i, lhs.UInt(i) / (rhs.UInt(i) | zeroMask));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001549 break;
Ben Clayton49d2c132019-03-14 12:21:53 +00001550 }
Ben Claytonbb8c8e22019-03-08 12:04:00 +00001551 case spv::OpSMod:
1552 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001553 auto a = lhs.Int(i);
1554 auto b = rhs.Int(i);
Ben Clayton49d2c132019-03-14 12:21:53 +00001555 auto zeroMask = CmpEQ(b, SIMD::Int(0));
1556 auto mod = a % (b | zeroMask);
Ben Claytonbb8c8e22019-03-08 12:04:00 +00001557 // If a and b have opposite signs, the remainder operation takes
1558 // the sign from a but OpSMod is supposed to take the sign of b.
1559 // Adding b will ensure that the result has the correct sign and
1560 // that it is still congruent to a modulo b.
1561 //
1562 // See also http://mathforum.org/library/drmath/view/52343.html
1563 auto signDiff = CmpNEQ(CmpGE(a, SIMD::Int(0)), CmpGE(b, SIMD::Int(0)));
1564 auto fixedMod = mod + (b & CmpNEQ(mod, SIMD::Int(0)) & signDiff);
1565 dst.emplace(i, As<SIMD::Float>(fixedMod));
1566 break;
1567 }
Ben Claytondd1e37e2019-02-28 19:59:15 +00001568 case spv::OpUMod:
Chris Forbes3ebf5832019-03-14 08:15:25 -07001569 {
1570 auto zeroMask = As<SIMD::UInt>(CmpEQ(rhs.Int(i), SIMD::Int(0)));
1571 dst.emplace(i, lhs.UInt(i) % (rhs.UInt(i) | zeroMask));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001572 break;
Chris Forbes3ebf5832019-03-14 08:15:25 -07001573 }
Ben Claytone95eeb12019-03-04 16:32:09 +00001574 case spv::OpIEqual:
Chris Forbes787b4462019-03-08 12:16:57 -08001575 case spv::OpLogicalEqual:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001576 dst.emplace(i, CmpEQ(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00001577 break;
1578 case spv::OpINotEqual:
Chris Forbes787b4462019-03-08 12:16:57 -08001579 case spv::OpLogicalNotEqual:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001580 dst.emplace(i, CmpNEQ(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00001581 break;
1582 case spv::OpUGreaterThan:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001583 dst.emplace(i, CmpGT(lhs.UInt(i), rhs.UInt(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00001584 break;
1585 case spv::OpSGreaterThan:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001586 dst.emplace(i, CmpGT(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00001587 break;
1588 case spv::OpUGreaterThanEqual:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001589 dst.emplace(i, CmpGE(lhs.UInt(i), rhs.UInt(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00001590 break;
1591 case spv::OpSGreaterThanEqual:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001592 dst.emplace(i, CmpGE(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00001593 break;
1594 case spv::OpULessThan:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001595 dst.emplace(i, CmpLT(lhs.UInt(i), rhs.UInt(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00001596 break;
1597 case spv::OpSLessThan:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001598 dst.emplace(i, CmpLT(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00001599 break;
1600 case spv::OpULessThanEqual:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001601 dst.emplace(i, CmpLE(lhs.UInt(i), rhs.UInt(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00001602 break;
1603 case spv::OpSLessThanEqual:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001604 dst.emplace(i, CmpLE(lhs.Int(i), rhs.Int(i)));
Ben Claytone95eeb12019-03-04 16:32:09 +00001605 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001606 case spv::OpFAdd:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001607 dst.emplace(i, lhs.Float(i) + rhs.Float(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001608 break;
1609 case spv::OpFSub:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001610 dst.emplace(i, lhs.Float(i) - rhs.Float(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001611 break;
Chris Forbes9d931532019-03-08 09:53:03 -08001612 case spv::OpFMul:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001613 dst.emplace(i, lhs.Float(i) * rhs.Float(i));
Chris Forbes9d931532019-03-08 09:53:03 -08001614 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001615 case spv::OpFDiv:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001616 dst.emplace(i, lhs.Float(i) / rhs.Float(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001617 break;
Ben Claytonec1aeb82019-03-04 19:33:27 +00001618 case spv::OpFOrdEqual:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001619 dst.emplace(i, CmpEQ(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00001620 break;
1621 case spv::OpFUnordEqual:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001622 dst.emplace(i, CmpUEQ(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00001623 break;
1624 case spv::OpFOrdNotEqual:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001625 dst.emplace(i, CmpNEQ(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00001626 break;
1627 case spv::OpFUnordNotEqual:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001628 dst.emplace(i, CmpUNEQ(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00001629 break;
1630 case spv::OpFOrdLessThan:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001631 dst.emplace(i, CmpLT(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00001632 break;
1633 case spv::OpFUnordLessThan:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001634 dst.emplace(i, CmpULT(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00001635 break;
1636 case spv::OpFOrdGreaterThan:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001637 dst.emplace(i, CmpGT(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00001638 break;
1639 case spv::OpFUnordGreaterThan:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001640 dst.emplace(i, CmpUGT(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00001641 break;
1642 case spv::OpFOrdLessThanEqual:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001643 dst.emplace(i, CmpLE(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00001644 break;
1645 case spv::OpFUnordLessThanEqual:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001646 dst.emplace(i, CmpULE(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00001647 break;
1648 case spv::OpFOrdGreaterThanEqual:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001649 dst.emplace(i, CmpGE(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00001650 break;
1651 case spv::OpFUnordGreaterThanEqual:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001652 dst.emplace(i, CmpUGE(lhs.Float(i), rhs.Float(i)));
Ben Claytonec1aeb82019-03-04 19:33:27 +00001653 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001654 case spv::OpShiftRightLogical:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001655 dst.emplace(i, lhs.UInt(i) >> rhs.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001656 break;
1657 case spv::OpShiftRightArithmetic:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001658 dst.emplace(i, lhs.Int(i) >> rhs.Int(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001659 break;
1660 case spv::OpShiftLeftLogical:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001661 dst.emplace(i, lhs.UInt(i) << rhs.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001662 break;
1663 case spv::OpBitwiseOr:
1664 case spv::OpLogicalOr:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001665 dst.emplace(i, lhs.UInt(i) | rhs.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001666 break;
1667 case spv::OpBitwiseXor:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001668 dst.emplace(i, lhs.UInt(i) ^ rhs.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001669 break;
1670 case spv::OpBitwiseAnd:
1671 case spv::OpLogicalAnd:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001672 dst.emplace(i, lhs.UInt(i) & rhs.UInt(i));
Ben Claytondd1e37e2019-02-28 19:59:15 +00001673 break;
Chris Forbese86b6dc2019-03-01 09:08:47 -08001674 case spv::OpSMulExtended:
1675 // Extended ops: result is a structure containing two members of the same type as lhs & rhs.
1676 // In our flat view then, component i is the i'th component of the first member;
1677 // component i + N is the i'th component of the second member.
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001678 dst.emplace(i, lhs.Int(i) * rhs.Int(i));
1679 dst.emplace(i + lhsType.sizeInComponents, MulHigh(lhs.Int(i), rhs.Int(i)));
Chris Forbese86b6dc2019-03-01 09:08:47 -08001680 break;
1681 case spv::OpUMulExtended:
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001682 dst.emplace(i, lhs.UInt(i) * rhs.UInt(i));
1683 dst.emplace(i + lhsType.sizeInComponents, MulHigh(lhs.UInt(i), rhs.UInt(i)));
Chris Forbese86b6dc2019-03-01 09:08:47 -08001684 break;
Ben Claytondd1e37e2019-02-28 19:59:15 +00001685 default:
1686 UNIMPLEMENTED("Unhandled binary operator %s", OpcodeName(insn.opcode()).c_str());
1687 }
1688 }
1689 }
1690
Chris Forbes2b287cc2019-03-01 13:24:17 -08001691 void SpirvShader::EmitDot(InsnIterator insn, SpirvRoutine *routine) const
1692 {
1693 auto &type = getType(insn.word(1));
1694 assert(type.sizeInComponents == 1);
1695 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1696 auto &lhsType = getType(getObject(insn.word(3)).type);
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001697 auto lhs = GenericValue(this, routine, insn.word(3));
1698 auto rhs = GenericValue(this, routine, insn.word(4));
Chris Forbes2b287cc2019-03-01 13:24:17 -08001699
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001700 dst.emplace(0, Dot(lhsType.sizeInComponents, lhs, rhs));
Chris Forbes2b287cc2019-03-01 13:24:17 -08001701 }
1702
Ben Claytonbf943f62019-03-05 12:57:39 +00001703 void SpirvShader::EmitSelect(InsnIterator insn, SpirvRoutine *routine) const
1704 {
1705 auto &type = getType(insn.word(1));
1706 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001707 auto cond = GenericValue(this, routine, insn.word(3));
1708 auto lhs = GenericValue(this, routine, insn.word(4));
1709 auto rhs = GenericValue(this, routine, insn.word(5));
Ben Claytonbf943f62019-03-05 12:57:39 +00001710
1711 for (auto i = 0u; i < type.sizeInComponents; i++)
1712 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001713 dst.emplace(i, (cond.Int(i) & lhs.Int(i)) | (~cond.Int(i) & rhs.Int(i))); // FIXME: IfThenElse()
Ben Claytonbf943f62019-03-05 12:57:39 +00001714 }
1715 }
1716
Chris Forbes9667a5b2019-03-07 09:26:48 -08001717 void SpirvShader::EmitExtendedInstruction(InsnIterator insn, SpirvRoutine *routine) const
1718 {
1719 auto &type = getType(insn.word(1));
1720 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
1721 auto extInstIndex = static_cast<GLSLstd450>(insn.word(4));
1722
1723 switch (extInstIndex)
1724 {
1725 case GLSLstd450FAbs:
1726 {
1727 auto src = GenericValue(this, routine, insn.word(5));
1728 for (auto i = 0u; i < type.sizeInComponents; i++)
1729 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001730 dst.emplace(i, Abs(src.Float(i)));
Chris Forbes9667a5b2019-03-07 09:26:48 -08001731 }
1732 break;
1733 }
1734 case GLSLstd450SAbs:
1735 {
1736 auto src = GenericValue(this, routine, insn.word(5));
1737 for (auto i = 0u; i < type.sizeInComponents; i++)
1738 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001739 dst.emplace(i, Abs(src.Int(i)));
Chris Forbes9667a5b2019-03-07 09:26:48 -08001740 }
1741 break;
1742 }
Chris Forbes15dff362019-03-08 11:31:31 -08001743 case GLSLstd450Cross:
1744 {
1745 auto lhs = GenericValue(this, routine, insn.word(5));
1746 auto rhs = GenericValue(this, routine, insn.word(6));
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001747 dst.emplace(0, lhs.Float(1) * rhs.Float(2) - rhs.Float(1) * lhs.Float(2));
1748 dst.emplace(1, lhs.Float(2) * rhs.Float(0) - rhs.Float(2) * lhs.Float(0));
1749 dst.emplace(2, lhs.Float(0) * rhs.Float(1) - rhs.Float(0) * lhs.Float(1));
Chris Forbes15dff362019-03-08 11:31:31 -08001750 break;
1751 }
Chris Forbesc212bbd2019-03-08 12:02:27 -08001752 case GLSLstd450Floor:
1753 {
1754 auto src = GenericValue(this, routine, insn.word(5));
1755 for (auto i = 0u; i < type.sizeInComponents; i++)
1756 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001757 dst.emplace(i, Floor(src.Float(i)));
Chris Forbesc212bbd2019-03-08 12:02:27 -08001758 }
1759 break;
1760 }
Chris Forbesdd172cc2019-03-08 13:36:40 -08001761 case GLSLstd450Trunc:
1762 {
1763 auto src = GenericValue(this, routine, insn.word(5));
1764 for (auto i = 0u; i < type.sizeInComponents; i++)
1765 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001766 dst.emplace(i, Trunc(src.Float(i)));
Chris Forbesdd172cc2019-03-08 13:36:40 -08001767 }
1768 break;
1769 }
1770 case GLSLstd450Ceil:
1771 {
1772 auto src = GenericValue(this, routine, insn.word(5));
1773 for (auto i = 0u; i < type.sizeInComponents; i++)
1774 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001775 dst.emplace(i, Ceil(src.Float(i)));
Chris Forbesdd172cc2019-03-08 13:36:40 -08001776 }
1777 break;
1778 }
1779 case GLSLstd450Fract:
1780 {
1781 auto src = GenericValue(this, routine, insn.word(5));
1782 for (auto i = 0u; i < type.sizeInComponents; i++)
1783 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001784 dst.emplace(i, Frac(src.Float(i)));
Chris Forbesdd172cc2019-03-08 13:36:40 -08001785 }
1786 break;
1787 }
1788 case GLSLstd450Round:
1789 {
1790 auto src = GenericValue(this, routine, insn.word(5));
1791 for (auto i = 0u; i < type.sizeInComponents; i++)
1792 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001793 dst.emplace(i, Round(src.Float(i)));
Chris Forbesdd172cc2019-03-08 13:36:40 -08001794 }
1795 break;
1796 }
1797 case GLSLstd450RoundEven:
1798 {
1799 auto src = GenericValue(this, routine, insn.word(5));
1800 for (auto i = 0u; i < type.sizeInComponents; i++)
1801 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001802 auto x = Round(src.Float(i));
Chris Forbesdd172cc2019-03-08 13:36:40 -08001803 // dst = round(src) + ((round(src) < src) * 2 - 1) * (fract(src) == 0.5) * isOdd(round(src));
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001804 dst.emplace(i, x + ((SIMD::Float(CmpLT(x, src.Float(i)) & SIMD::Int(1)) * SIMD::Float(2.0f)) - SIMD::Float(1.0f)) *
1805 SIMD::Float(CmpEQ(Frac(src.Float(i)), SIMD::Float(0.5f)) & SIMD::Int(1)) * SIMD::Float(Int4(x) & SIMD::Int(1)));
Chris Forbesdd172cc2019-03-08 13:36:40 -08001806 }
1807 break;
1808 }
Chris Forbesdb170772019-03-08 14:50:44 -08001809 case GLSLstd450FMin:
1810 {
1811 auto lhs = GenericValue(this, routine, insn.word(5));
1812 auto rhs = GenericValue(this, routine, insn.word(6));
1813 for (auto i = 0u; i < type.sizeInComponents; i++)
1814 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001815 dst.emplace(i, Min(lhs.Float(i), rhs.Float(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08001816 }
1817 break;
1818 }
1819 case GLSLstd450FMax:
1820 {
1821 auto lhs = GenericValue(this, routine, insn.word(5));
1822 auto rhs = GenericValue(this, routine, insn.word(6));
1823 for (auto i = 0u; i < type.sizeInComponents; i++)
1824 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001825 dst.emplace(i, Max(lhs.Float(i), rhs.Float(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08001826 }
1827 break;
1828 }
1829 case GLSLstd450SMin:
1830 {
1831 auto lhs = GenericValue(this, routine, insn.word(5));
1832 auto rhs = GenericValue(this, routine, insn.word(6));
1833 for (auto i = 0u; i < type.sizeInComponents; i++)
1834 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001835 dst.emplace(i, Min(lhs.Int(i), rhs.Int(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08001836 }
1837 break;
1838 }
1839 case GLSLstd450SMax:
1840 {
1841 auto lhs = GenericValue(this, routine, insn.word(5));
1842 auto rhs = GenericValue(this, routine, insn.word(6));
1843 for (auto i = 0u; i < type.sizeInComponents; i++)
1844 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001845 dst.emplace(i, Max(lhs.Int(i), rhs.Int(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08001846 }
1847 break;
1848 }
1849 case GLSLstd450UMin:
1850 {
1851 auto lhs = GenericValue(this, routine, insn.word(5));
1852 auto rhs = GenericValue(this, routine, insn.word(6));
1853 for (auto i = 0u; i < type.sizeInComponents; i++)
1854 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001855 dst.emplace(i, Min(lhs.UInt(i), rhs.UInt(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08001856 }
1857 break;
1858 }
1859 case GLSLstd450UMax:
1860 {
1861 auto lhs = GenericValue(this, routine, insn.word(5));
1862 auto rhs = GenericValue(this, routine, insn.word(6));
1863 for (auto i = 0u; i < type.sizeInComponents; i++)
1864 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001865 dst.emplace(i, Max(lhs.UInt(i), rhs.UInt(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08001866 }
1867 break;
1868 }
1869 case GLSLstd450Step:
1870 {
1871 auto edge = GenericValue(this, routine, insn.word(5));
1872 auto x = GenericValue(this, routine, insn.word(6));
1873 for (auto i = 0u; i < type.sizeInComponents; i++)
1874 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001875 dst.emplace(i, CmpNLT(x.Float(i), edge.Float(i)) & As<SIMD::Int>(SIMD::Float(1.0f)));
Chris Forbesdb170772019-03-08 14:50:44 -08001876 }
1877 break;
1878 }
1879 case GLSLstd450SmoothStep:
1880 {
1881 auto edge0 = GenericValue(this, routine, insn.word(5));
1882 auto edge1 = GenericValue(this, routine, insn.word(6));
1883 auto x = GenericValue(this, routine, insn.word(7));
1884 for (auto i = 0u; i < type.sizeInComponents; i++)
1885 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001886 auto tx = Min(Max((x.Float(i) - edge0.Float(i)) /
1887 (edge1.Float(i) - edge0.Float(i)), SIMD::Float(0.0f)), SIMD::Float(1.0f));
Chris Forbesdb170772019-03-08 14:50:44 -08001888 dst.emplace(i, tx * tx * (Float4(3.0f) - Float4(2.0f) * tx));
1889 }
1890 break;
1891 }
1892 case GLSLstd450FMix:
1893 {
1894 auto x = GenericValue(this, routine, insn.word(5));
1895 auto y = GenericValue(this, routine, insn.word(6));
1896 auto a = GenericValue(this, routine, insn.word(7));
1897 for (auto i = 0u; i < type.sizeInComponents; i++)
1898 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001899 dst.emplace(i, a.Float(i) * (y.Float(i) - x.Float(i)) + x.Float(i));
Chris Forbesdb170772019-03-08 14:50:44 -08001900 }
1901 break;
1902 }
1903 case GLSLstd450FClamp:
1904 {
1905 auto x = GenericValue(this, routine, insn.word(5));
1906 auto minVal = GenericValue(this, routine, insn.word(6));
1907 auto maxVal = GenericValue(this, routine, insn.word(7));
1908 for (auto i = 0u; i < type.sizeInComponents; i++)
1909 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001910 dst.emplace(i, Min(Max(x.Float(i), minVal.Float(i)), maxVal.Float(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08001911 }
1912 break;
1913 }
1914 case GLSLstd450SClamp:
1915 {
1916 auto x = GenericValue(this, routine, insn.word(5));
1917 auto minVal = GenericValue(this, routine, insn.word(6));
1918 auto maxVal = GenericValue(this, routine, insn.word(7));
1919 for (auto i = 0u; i < type.sizeInComponents; i++)
1920 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001921 dst.emplace(i, Min(Max(x.Int(i), minVal.Int(i)), maxVal.Int(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08001922 }
1923 break;
1924 }
1925 case GLSLstd450UClamp:
1926 {
1927 auto x = GenericValue(this, routine, insn.word(5));
1928 auto minVal = GenericValue(this, routine, insn.word(6));
1929 auto maxVal = GenericValue(this, routine, insn.word(7));
1930 for (auto i = 0u; i < type.sizeInComponents; i++)
1931 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001932 dst.emplace(i, Min(Max(x.UInt(i), minVal.UInt(i)), maxVal.UInt(i)));
Chris Forbesdb170772019-03-08 14:50:44 -08001933 }
1934 break;
1935 }
1936 case GLSLstd450FSign:
1937 {
1938 auto src = GenericValue(this, routine, insn.word(5));
1939 for (auto i = 0u; i < type.sizeInComponents; i++)
1940 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001941 auto neg = As<SIMD::Int>(CmpLT(src.Float(i), SIMD::Float(-0.0f))) & As<SIMD::Int>(SIMD::Float(-1.0f));
1942 auto pos = As<SIMD::Int>(CmpNLE(src.Float(i), SIMD::Float(+0.0f))) & As<SIMD::Int>(SIMD::Float(1.0f));
Ben Clayton093be462019-03-08 08:37:24 +00001943 dst.emplace(i, neg | pos);
Chris Forbesdb170772019-03-08 14:50:44 -08001944 }
1945 break;
1946 }
1947 case GLSLstd450SSign:
1948 {
1949 auto src = GenericValue(this, routine, insn.word(5));
1950 for (auto i = 0u; i < type.sizeInComponents; i++)
1951 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001952 auto neg = CmpLT(src.Int(i), SIMD::Int(0)) & SIMD::Int(-1);
1953 auto pos = CmpNLE(src.Int(i), SIMD::Int(0)) & SIMD::Int(1);
Ben Clayton093be462019-03-08 08:37:24 +00001954 dst.emplace(i, neg | pos);
Chris Forbesdb170772019-03-08 14:50:44 -08001955 }
1956 break;
1957 }
Chris Forbes868ed902019-03-13 17:39:45 -07001958 case GLSLstd450Reflect:
1959 {
1960 auto I = GenericValue(this, routine, insn.word(5));
1961 auto N = GenericValue(this, routine, insn.word(6));
1962
1963 SIMD::Float d = Dot(type.sizeInComponents, I, N);
1964
1965 for (auto i = 0u; i < type.sizeInComponents; i++)
1966 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001967 dst.emplace(i, I.Float(i) - SIMD::Float(2.0f) * d * N.Float(i));
Chris Forbes868ed902019-03-13 17:39:45 -07001968 }
1969 break;
1970 }
1971 case GLSLstd450Refract:
1972 {
1973 auto I = GenericValue(this, routine, insn.word(5));
1974 auto N = GenericValue(this, routine, insn.word(6));
1975 auto eta = GenericValue(this, routine, insn.word(7));
1976
1977 SIMD::Float d = Dot(type.sizeInComponents, I, N);
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001978 SIMD::Float k = SIMD::Float(1.0f) - eta.Float(0) * eta.Float(0) * (SIMD::Float(1.0f) - d * d);
Chris Forbes868ed902019-03-13 17:39:45 -07001979 SIMD::Int pos = CmpNLT(k, SIMD::Float(0.0f));
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001980 SIMD::Float t = (eta.Float(0) * d + Sqrt(k));
Chris Forbes868ed902019-03-13 17:39:45 -07001981
1982 for (auto i = 0u; i < type.sizeInComponents; i++)
1983 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001984 dst.emplace(i, pos & As<SIMD::Int>(eta.Float(0) * I.Float(i) - t * N.Float(i)));
Chris Forbes868ed902019-03-13 17:39:45 -07001985 }
1986 break;
1987 }
1988 case GLSLstd450FaceForward:
1989 {
1990 auto N = GenericValue(this, routine, insn.word(5));
1991 auto I = GenericValue(this, routine, insn.word(6));
1992 auto Nref = GenericValue(this, routine, insn.word(7));
1993
1994 SIMD::Float d = Dot(type.sizeInComponents, I, Nref);
1995 SIMD::Int neg = CmpLT(d, SIMD::Float(0.0f));
1996
1997 for (auto i = 0u; i < type.sizeInComponents; i++)
1998 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00001999 auto n = N.Float(i);
2000 dst.emplace(i, (neg & As<SIMD::Int>(n)) | (~neg & As<SIMD::Int>(-n)));
Chris Forbes868ed902019-03-13 17:39:45 -07002001 }
2002 break;
2003 }
2004 case GLSLstd450Length:
2005 {
2006 auto x = GenericValue(this, routine, insn.word(5));
2007 SIMD::Float d = Dot(getType(getObject(insn.word(5)).type).sizeInComponents, x, x);
2008
2009 dst.emplace(0, Sqrt(d));
2010 break;
2011 }
2012 case GLSLstd450Normalize:
2013 {
2014 auto x = GenericValue(this, routine, insn.word(5));
2015 SIMD::Float d = Dot(getType(getObject(insn.word(5)).type).sizeInComponents, x, x);
2016 SIMD::Float invLength = SIMD::Float(1.0f) / Sqrt(d);
2017
2018 for (auto i = 0u; i < type.sizeInComponents; i++)
2019 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002020 dst.emplace(i, invLength * x.Float(i));
Chris Forbes868ed902019-03-13 17:39:45 -07002021 }
2022 break;
2023 }
2024 case GLSLstd450Distance:
2025 {
2026 auto p0 = GenericValue(this, routine, insn.word(5));
2027 auto p1 = GenericValue(this, routine, insn.word(6));
2028 auto p0Type = getType(getObject(insn.word(5)).type);
2029
2030 // sqrt(dot(p0-p1, p0-p1))
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002031 SIMD::Float d = (p0.Float(0) - p1.Float(0)) * (p0.Float(0) - p1.Float(0));
Chris Forbes868ed902019-03-13 17:39:45 -07002032
2033 for (auto i = 1u; i < p0Type.sizeInComponents; i++)
2034 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002035 d += (p0.Float(i) - p1.Float(i)) * (p0.Float(i) - p1.Float(i));
Chris Forbes868ed902019-03-13 17:39:45 -07002036 }
2037
2038 dst.emplace(0, Sqrt(d));
2039 break;
2040 }
Chris Forbes9667a5b2019-03-07 09:26:48 -08002041 default:
2042 UNIMPLEMENTED("Unhandled ExtInst %d", extInstIndex);
2043 }
2044 }
2045
Chris Forbes868ed902019-03-13 17:39:45 -07002046 SIMD::Float SpirvShader::Dot(unsigned numComponents, GenericValue const & x, GenericValue const & y) const
2047 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002048 SIMD::Float d = x.Float(0) * y.Float(0);
Chris Forbes868ed902019-03-13 17:39:45 -07002049
2050 for (auto i = 1u; i < numComponents; i++)
2051 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002052 d += x.Float(i) * y.Float(i);
Chris Forbes868ed902019-03-13 17:39:45 -07002053 }
2054
2055 return d;
2056 }
2057
Chris Forbes0785f692019-03-08 09:09:18 -08002058 void SpirvShader::EmitAny(InsnIterator insn, SpirvRoutine *routine) const
2059 {
2060 auto &type = getType(insn.word(1));
2061 assert(type.sizeInComponents == 1);
2062 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2063 auto &srcType = getType(getObject(insn.word(3)).type);
2064 auto src = GenericValue(this, routine, insn.word(3));
2065
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002066 SIMD::UInt result = src.UInt(0);
Chris Forbes0785f692019-03-08 09:09:18 -08002067
2068 for (auto i = 1u; i < srcType.sizeInComponents; i++)
2069 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002070 result |= src.UInt(i);
Chris Forbes0785f692019-03-08 09:09:18 -08002071 }
2072
Ben Clayton093be462019-03-08 08:37:24 +00002073 dst.emplace(0, result);
Chris Forbes0785f692019-03-08 09:09:18 -08002074 }
2075
2076 void SpirvShader::EmitAll(InsnIterator insn, SpirvRoutine *routine) const
2077 {
2078 auto &type = getType(insn.word(1));
2079 assert(type.sizeInComponents == 1);
2080 auto &dst = routine->createIntermediate(insn.word(2), type.sizeInComponents);
2081 auto &srcType = getType(getObject(insn.word(3)).type);
2082 auto src = GenericValue(this, routine, insn.word(3));
2083
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002084 SIMD::UInt result = src.UInt(0);
Chris Forbes0785f692019-03-08 09:09:18 -08002085
2086 for (auto i = 1u; i < srcType.sizeInComponents; i++)
2087 {
Ben Clayton9b62c5e2019-03-08 09:32:34 +00002088 result &= src.UInt(i);
Chris Forbes0785f692019-03-08 09:09:18 -08002089 }
2090
Ben Clayton093be462019-03-08 08:37:24 +00002091 dst.emplace(0, result);
Chris Forbes0785f692019-03-08 09:09:18 -08002092 }
2093
Chris Forbesc61271e2019-02-19 17:01:28 -08002094 void SpirvShader::emitEpilog(SpirvRoutine *routine) const
2095 {
2096 for (auto insn : *this)
2097 {
2098 switch (insn.opcode())
2099 {
2100 case spv::OpVariable:
2101 {
Ben Claytonab51bbf2019-02-20 14:36:27 +00002102 ObjectID resultId = insn.word(2);
Chris Forbesc61271e2019-02-19 17:01:28 -08002103 auto &object = getObject(resultId);
Ben Clayton9a162482019-02-25 11:54:43 +00002104 auto &objectTy = getType(object.type);
2105 if (object.kind == Object::Kind::InterfaceVariable && objectTy.storageClass == spv::StorageClassOutput)
Chris Forbesc61271e2019-02-19 17:01:28 -08002106 {
2107 auto &dst = routine->getValue(resultId);
2108 int offset = 0;
2109 VisitInterface(resultId,
2110 [&](Decorations const &d, AttribType type) {
2111 auto scalarSlot = d.Location << 2 | d.Component;
2112 routine->outputs[scalarSlot] = dst[offset++];
2113 });
2114 }
2115 break;
2116 }
2117 default:
2118 break;
2119 }
2120 }
2121 }
Ben Clayton76e9bc02019-02-26 15:02:18 +00002122
2123 SpirvRoutine::SpirvRoutine(vk::PipelineLayout const *pipelineLayout) :
2124 pipelineLayout(pipelineLayout)
2125 {
2126 }
2127
Chris Forbesc25b8072018-12-10 15:10:39 -08002128}