1 // Copyright 2018 The SwiftShader Authors. All Rights Reserved.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
15 #include <spirv/unified1/spirv.hpp>
16 #include "SpirvShader.hpp"
17 #include "System/Math.hpp"
18 #include "Vulkan/VkDebug.hpp"
19 #include "Device/Config.hpp"
23 volatile int SpirvShader::serialCounter = 1; // Start at 1, 0 is invalid shader.
25 SpirvShader::SpirvShader(InsnStore const &insns)
26 : insns{insns}, inputs{MAX_INTERFACE_COMPONENTS},
27 outputs{MAX_INTERFACE_COMPONENTS},
28 serialID{serialCounter++}, modes{}
30 // Simplifying assumptions (to be satisfied by earlier transformations)
31 // - There is exactly one entrypoint in the module, and it's the one we want
32 // - The only input/output OpVariables present are those used by the entrypoint
34 for (auto insn : *this)
36 switch (insn.opcode())
38 case spv::OpExecutionMode:
39 ProcessExecutionMode(insn);
44 auto targetId = insn.word(1);
45 auto decoration = static_cast<spv::Decoration>(insn.word(2));
46 decorations[targetId].Apply(
48 insn.wordCount() > 3 ? insn.word(3) : 0);
50 if (decoration == spv::DecorationCentroid)
51 modes.NeedsCentroid = true;
55 case spv::OpMemberDecorate:
57 auto targetId = insn.word(1);
58 auto memberIndex = insn.word(2);
59 auto &d = memberDecorations[targetId];
60 if (memberIndex >= d.size())
61 d.resize(memberIndex + 1); // on demand; exact size would require another pass...
62 auto decoration = static_cast<spv::Decoration>(insn.word(3));
65 insn.wordCount() > 4 ? insn.word(4) : 0);
67 if (decoration == spv::DecorationCentroid)
68 modes.NeedsCentroid = true;
72 case spv::OpDecorationGroup:
73 // Nothing to do here. We don't need to record the definition of the group; we'll just have
74 // the bundle of decorations float around. If we were to ever walk the decorations directly,
75 // we might think about introducing this as a real Object.
78 case spv::OpGroupDecorate:
80 auto const &srcDecorations = decorations[insn.word(1)];
81 for (auto i = 2u; i < insn.wordCount(); i++)
83 // remaining operands are targets to apply the group to.
84 decorations[insn.word(i)].Apply(srcDecorations);
89 case spv::OpGroupMemberDecorate:
91 auto const &srcDecorations = decorations[insn.word(1)];
92 for (auto i = 2u; i < insn.wordCount(); i += 2)
94 // remaining operands are pairs of <id>, literal for members to apply to.
95 auto &d = memberDecorations[insn.word(i)];
96 auto memberIndex = insn.word(i + 1);
97 if (memberIndex >= d.size())
98 d.resize(memberIndex + 1); // on demand resize, see above...
99 d[memberIndex].Apply(srcDecorations);
104 case spv::OpTypeVoid:
105 case spv::OpTypeBool:
107 case spv::OpTypeFloat:
108 case spv::OpTypeVector:
109 case spv::OpTypeMatrix:
110 case spv::OpTypeImage:
111 case spv::OpTypeSampler:
112 case spv::OpTypeSampledImage:
113 case spv::OpTypeArray:
114 case spv::OpTypeRuntimeArray:
115 case spv::OpTypeStruct:
116 case spv::OpTypePointer:
117 case spv::OpTypeFunction:
119 auto resultId = insn.word(1);
120 auto &type = types[resultId];
121 type.definition = insn;
122 type.sizeInComponents = ComputeTypeSize(insn);
124 // A structure is a builtin block if it has a builtin
125 // member. All members of such a structure are builtins.
126 if (insn.opcode() == spv::OpTypeStruct)
128 auto d = memberDecorations.find(resultId);
129 if (d != memberDecorations.end())
131 for (auto &m : d->second)
135 type.isBuiltInBlock = true;
141 else if (insn.opcode() == spv::OpTypePointer)
143 auto pointeeType = insn.word(3);
144 type.isBuiltInBlock = getType(pointeeType).isBuiltInBlock;
149 case spv::OpVariable:
151 auto typeId = insn.word(1);
152 auto resultId = insn.word(2);
153 auto storageClass = static_cast<spv::StorageClass>(insn.word(3));
154 if (insn.wordCount() > 4)
155 UNIMPLEMENTED("Variable initializers not yet supported");
157 auto &object = defs[resultId];
158 object.kind = Object::Kind::Variable;
159 object.definition = insn;
160 object.storageClass = storageClass;
162 auto &type = getType(typeId);
163 auto &pointeeType = getType(type.definition.word(3));
165 // OpVariable's "size" is the size of the allocation required (the size of the pointee)
166 object.sizeInComponents = pointeeType.sizeInComponents;
167 object.isBuiltInBlock = type.isBuiltInBlock;
168 object.pointerBase = insn.word(2); // base is itself
172 if (storageClass == spv::StorageClassInput || storageClass == spv::StorageClassOutput)
174 ProcessInterfaceVariable(object);
179 case spv::OpConstant:
180 case spv::OpConstantComposite:
181 case spv::OpConstantFalse:
182 case spv::OpConstantTrue:
183 case spv::OpConstantNull:
185 auto typeId = insn.word(1);
186 auto resultId = insn.word(2);
187 auto &object = defs[resultId];
188 object.kind = Object::Kind::Constant;
189 object.definition = insn;
190 object.sizeInComponents = getType(typeId).sizeInComponents;
194 case spv::OpCapability:
195 // Various capabilities will be declared, but none affect our code generation at this point.
196 case spv::OpMemoryModel:
197 // Memory model does not affect our code generation until we decide to do Vulkan Memory Model support.
198 case spv::OpEntryPoint:
199 case spv::OpFunction:
200 case spv::OpFunctionEnd:
201 // Due to preprocessing, the entrypoint and its function provide no value.
203 case spv::OpExtInstImport:
204 // We will only support the GLSL 450 extended instruction set, so no point in tracking the ID we assign it.
205 // Valid shaders will not attempt to import any other instruction sets.
208 case spv::OpFunctionParameter:
209 case spv::OpFunctionCall:
210 case spv::OpSpecConstant:
211 case spv::OpSpecConstantComposite:
212 case spv::OpSpecConstantFalse:
213 case spv::OpSpecConstantOp:
214 case spv::OpSpecConstantTrue:
215 // These should have all been removed by preprocessing passes. If we see them here,
216 // our assumptions are wrong and we will probably generate wrong code.
217 UNIMPLEMENTED("These instructions should have already been lowered.");
221 case spv::OpAccessChain:
222 // Instructions that yield an ssavalue.
224 auto typeId = insn.word(1);
225 auto resultId = insn.word(2);
226 auto &object = defs[resultId];
227 object.kind = Object::Kind::Value;
228 object.definition = insn;
229 object.sizeInComponents = getType(typeId).sizeInComponents;
231 if (insn.opcode() == spv::OpAccessChain)
233 // interior ptr has two parts:
234 // - logical base ptr, common across all lanes and known at compile time
236 object.pointerBase = getObject(insn.word(3)).pointerBase;
243 // Don't need to do anything during analysis pass
247 modes.ContainsKill = true;
251 printf("Warning: ignored opcode %u\n", insn.opcode());
252 break; // This is OK, these passes are intentionally partial
257 void SpirvShader::ProcessInterfaceVariable(Object &object)
259 assert(object.storageClass == spv::StorageClassInput || object.storageClass == spv::StorageClassOutput);
261 auto &builtinInterface = (object.storageClass == spv::StorageClassInput) ? inputBuiltins : outputBuiltins;
262 auto &userDefinedInterface = (object.storageClass == spv::StorageClassInput) ? inputs : outputs;
264 auto resultId = object.definition.word(2);
265 if (object.isBuiltInBlock)
267 // walk the builtin block, registering each of its members separately.
268 auto ptrType = getType(object.definition.word(1)).definition;
269 assert(ptrType.opcode() == spv::OpTypePointer);
270 auto pointeeType = ptrType.word(3);
271 auto m = memberDecorations.find(pointeeType);
272 assert(m != memberDecorations.end()); // otherwise we wouldn't have marked the type chain
273 auto &structType = getType(pointeeType).definition;
276 for (auto &member : m->second)
278 auto &memberType = getType(structType.word(word));
280 if (member.HasBuiltIn)
282 builtinInterface[member.BuiltIn] = {resultId, offset, memberType.sizeInComponents};
285 offset += memberType.sizeInComponents;
291 auto d = decorations.find(resultId);
292 if (d != decorations.end() && d->second.HasBuiltIn)
294 builtinInterface[d->second.BuiltIn] = {resultId, 0, object.sizeInComponents};
298 object.kind = Object::Kind::InterfaceVariable;
299 VisitInterface(resultId,
300 [&userDefinedInterface](Decorations const &d, AttribType type) {
301 // Populate a single scalar slot in the interface from a collection of decorations and the intended component type.
302 auto scalarSlot = (d.Location << 2) | d.Component;
303 assert(scalarSlot >= 0 &&
304 scalarSlot < static_cast<int32_t>(userDefinedInterface.size()));
306 auto &slot = userDefinedInterface[scalarSlot];
309 slot.NoPerspective = d.NoPerspective;
310 slot.Centroid = d.Centroid;
315 void SpirvShader::ProcessExecutionMode(InsnIterator insn)
317 auto mode = static_cast<spv::ExecutionMode>(insn.word(2));
320 case spv::ExecutionModeEarlyFragmentTests:
321 modes.EarlyFragmentTests = true;
323 case spv::ExecutionModeDepthReplacing:
324 modes.DepthReplacing = true;
326 case spv::ExecutionModeDepthGreater:
327 modes.DepthGreater = true;
329 case spv::ExecutionModeDepthLess:
330 modes.DepthLess = true;
332 case spv::ExecutionModeDepthUnchanged:
333 modes.DepthUnchanged = true;
335 case spv::ExecutionModeLocalSize:
336 modes.LocalSizeX = insn.word(3);
337 modes.LocalSizeZ = insn.word(5);
338 modes.LocalSizeY = insn.word(4);
340 case spv::ExecutionModeOriginUpperLeft:
341 // This is always the case for a Vulkan shader. Do nothing.
344 UNIMPLEMENTED("No other execution modes are permitted");
348 uint32_t SpirvShader::ComputeTypeSize(sw::SpirvShader::InsnIterator insn)
350 // Types are always built from the bottom up (with the exception of forward ptrs, which
351 // don't appear in Vulkan shaders. Therefore, we can always assume our component parts have
352 // already been described (and so their sizes determined)
353 switch (insn.opcode())
355 case spv::OpTypeVoid:
356 case spv::OpTypeSampler:
357 case spv::OpTypeImage:
358 case spv::OpTypeSampledImage:
359 case spv::OpTypeFunction:
360 case spv::OpTypeRuntimeArray:
361 // Objects that don't consume any space.
362 // Descriptor-backed objects currently only need exist at compile-time.
363 // Runtime arrays don't appear in places where their size would be interesting
366 case spv::OpTypeBool:
367 case spv::OpTypeFloat:
369 // All the fundamental types are 1 component. If we ever add support for 8/16/64-bit components,
370 // we might need to change this, but only 32 bit components are required for Vulkan 1.1.
373 case spv::OpTypeVector:
374 case spv::OpTypeMatrix:
375 // Vectors and matrices both consume element count * element size.
376 return getType(insn.word(2)).sizeInComponents * insn.word(3);
378 case spv::OpTypeArray:
380 // Element count * element size. Array sizes come from constant ids.
381 auto arraySize = GetConstantInt(insn.word(3));
382 return getType(insn.word(2)).sizeInComponents * arraySize;
385 case spv::OpTypeStruct:
388 for (uint32_t i = 2u; i < insn.wordCount(); i++)
390 size += getType(insn.word(i)).sizeInComponents;
395 case spv::OpTypePointer:
396 // Runtime representation of a pointer is a per-lane index.
397 // Note: clients are expected to look through the pointer if they want the pointee size instead.
401 // Some other random insn.
402 UNIMPLEMENTED("Only types are supported");
407 int SpirvShader::VisitInterfaceInner(uint32_t id, Decorations d, F f) const
409 // Recursively walks variable definition and its type tree, taking into account
410 // any explicit Location or Component decorations encountered; where explicit
411 // Locations or Components are not specified, assigns them sequentially.
412 // Collected decorations are carried down toward the leaves and across
413 // siblings; Effect of decorations intentionally does not flow back up the tree.
415 // F is a functor to be called with the effective decoration set for every component.
417 // Returns the next available location, and calls f().
419 // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment.
421 ApplyDecorationsForId(&d, id);
423 auto const &obj = getType(id);
424 switch (obj.definition.opcode())
426 case spv::OpTypePointer:
427 return VisitInterfaceInner<F>(obj.definition.word(3), d, f);
428 case spv::OpTypeMatrix:
429 for (auto i = 0u; i < obj.definition.word(3); i++, d.Location++)
431 // consumes same components of N consecutive locations
432 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
435 case spv::OpTypeVector:
436 for (auto i = 0u; i < obj.definition.word(3); i++, d.Component++)
438 // consumes N consecutive components in the same location
439 VisitInterfaceInner<F>(obj.definition.word(2), d, f);
441 return d.Location + 1;
442 case spv::OpTypeFloat:
443 f(d, ATTRIBTYPE_FLOAT);
444 return d.Location + 1;
446 f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT);
447 return d.Location + 1;
448 case spv::OpTypeBool:
449 f(d, ATTRIBTYPE_UINT);
450 return d.Location + 1;
451 case spv::OpTypeStruct:
453 // iterate over members, which may themselves have Location/Component decorations
454 for (auto i = 0u; i < obj.definition.wordCount() - 2; i++)
456 ApplyDecorationsForIdMember(&d, id, i);
457 d.Location = VisitInterfaceInner<F>(obj.definition.word(i + 2), d, f);
458 d.Component = 0; // Implicit locations always have component=0
462 case spv::OpTypeArray:
464 auto arraySize = GetConstantInt(obj.definition.word(3));
465 for (auto i = 0u; i < arraySize; i++)
467 d.Location = VisitInterfaceInner<F>(obj.definition.word(2), d, f);
472 // Intentionally partial; most opcodes do not participate in type hierarchies
478 void SpirvShader::VisitInterface(uint32_t id, F f) const
480 // Walk a variable definition and call f for each component in it.
482 ApplyDecorationsForId(&d, id);
484 auto def = getObject(id).definition;
485 assert(def.opcode() == spv::OpVariable);
486 VisitInterfaceInner<F>(def.word(1), d, f);
489 Int4 SpirvShader::WalkAccessChain(uint32_t id, uint32_t numIndexes, uint32_t const *indexIds, SpirvRoutine *routine) const
491 // TODO: think about decorations, to make this work on location based interfaces
492 // TODO: think about explicit layout (UBO/SSBO) storage classes
493 // TODO: avoid doing per-lane work in some cases if we can?
495 int constantOffset = 0;
496 Int4 dynamicOffset = Int4(0);
497 auto & baseObject = getObject(id);
498 auto typeId = baseObject.definition.word(1);
500 if (baseObject.kind == Object::Kind::Value)
501 dynamicOffset += As<Int4>(routine->getValue(id)[0]);
503 for (auto i = 0u; i < numIndexes; i++)
505 auto & type = getType(typeId);
506 switch (type.definition.opcode())
508 case spv::OpTypeStruct:
510 int memberIndex = GetConstantInt(indexIds[i]);
511 int offsetIntoStruct = 0;
512 for (auto j = 0; j < memberIndex; j++) {
513 offsetIntoStruct += getType(type.definition.word(2 + memberIndex)).sizeInComponents;
515 constantOffset += offsetIntoStruct;
519 case spv::OpTypeVector:
520 case spv::OpTypeMatrix:
521 case spv::OpTypeArray:
523 auto stride = getType(type.definition.word(2)).sizeInComponents;
524 auto & obj = getObject(indexIds[i]);
525 if (obj.kind == Object::Kind::Constant)
526 constantOffset += stride * GetConstantInt(indexIds[i]);
528 dynamicOffset += Int4(stride) * As<Int4>(routine->getValue(indexIds[i])[0]);
533 UNIMPLEMENTED("Unexpected type in WalkAccessChain");
537 return dynamicOffset + Int4(constantOffset);
540 void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
544 case spv::DecorationLocation:
546 Location = static_cast<int32_t>(arg);
548 case spv::DecorationComponent:
552 case spv::DecorationBuiltIn:
554 BuiltIn = static_cast<spv::BuiltIn>(arg);
556 case spv::DecorationFlat:
559 case spv::DecorationNoPerspective:
560 NoPerspective = true;
562 case spv::DecorationCentroid:
565 case spv::DecorationBlock:
568 case spv::DecorationBufferBlock:
572 // Intentionally partial, there are many decorations we just don't care about.
577 void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src)
579 // Apply a decoration group to this set of decorations
583 BuiltIn = src.BuiltIn;
589 Location = src.Location;
592 if (src.HasComponent)
595 Component = src.Component;
599 NoPerspective |= src.NoPerspective;
600 Centroid |= src.Centroid;
602 BufferBlock |= src.BufferBlock;
605 void SpirvShader::ApplyDecorationsForId(Decorations *d, uint32_t id) const
607 auto it = decorations.find(id);
608 if (it != decorations.end())
609 d->Apply(it->second);
612 void SpirvShader::ApplyDecorationsForIdMember(Decorations *d, uint32_t id, uint32_t member) const
614 auto it = memberDecorations.find(id);
615 if (it != memberDecorations.end() && member < it->second.size())
617 d->Apply(it->second[member]);
621 uint32_t SpirvShader::GetConstantInt(uint32_t id) const
623 // Slightly hackish access to constants very early in translation.
624 // General consumption of constants by other instructions should
625 // probably be just lowered to Reactor.
627 // TODO: not encountered yet since we only use this for array sizes etc,
628 // but is possible to construct integer constant 0 via OpConstantNull.
629 auto insn = getObject(id).definition;
630 assert(insn.opcode() == spv::OpConstant);
631 assert(getType(insn.word(1)).definition.opcode() == spv::OpTypeInt);
637 void SpirvShader::emitEarly(SpirvRoutine *routine) const
639 for (auto insn : *this)
641 switch (insn.opcode())
643 case spv::OpVariable:
645 auto resultId = insn.word(2);
646 auto &object = getObject(resultId);
647 // TODO: what to do about zero-slot objects?
648 if (object.sizeInComponents > 0)
650 routine->createLvalue(insn.word(2), object.sizeInComponents);
655 // Nothing else produces interface variables, so can all be safely ignored.
661 void SpirvShader::emit(SpirvRoutine *routine) const
663 for (auto insn : *this)
665 switch (insn.opcode())
667 case spv::OpVariable:
669 auto resultId = insn.word(2);
670 auto &object = getObject(resultId);
671 if (object.kind == Object::Kind::InterfaceVariable && object.storageClass == spv::StorageClassInput)
673 auto &dst = routine->getValue(resultId);
675 VisitInterface(resultId,
676 [&](Decorations const &d, AttribType type) {
677 auto scalarSlot = d.Location << 2 | d.Component;
678 dst[offset++] = (*routine->inputs)[scalarSlot];
685 auto &object = getObject(insn.word(2));
686 auto &type = getType(insn.word(1));
687 auto &pointer = getObject(insn.word(3));
688 routine->createLvalue(insn.word(2), type.sizeInComponents); // TODO: this should be an ssavalue!
689 auto &pointerBase = getObject(pointer.pointerBase);
691 if (pointerBase.storageClass == spv::StorageClassImage ||
692 pointerBase.storageClass == spv::StorageClassUniform ||
693 pointerBase.storageClass == spv::StorageClassUniformConstant)
695 UNIMPLEMENTED("Descriptor-backed load not yet implemented");
698 SpirvRoutine::Value& ptrBase = routine->getValue(pointer.pointerBase);
699 auto & dst = routine->getValue(insn.word(2));
701 if (pointer.kind == Object::Kind::Value)
703 auto offsets = As<Int4>(routine->getValue(insn.word(3)));
704 for (auto i = 0u; i < object.sizeInComponents; i++)
706 // i wish i had a Float,Float,Float,Float constructor here..
708 for (int j = 0; j < 4; j++)
709 v = Insert(v, Extract(ptrBase[Int(i) + Extract(offsets, j)], j), j);
715 // no divergent offsets to worry about
716 for (auto i = 0u; i < object.sizeInComponents; i++)
723 case spv::OpAccessChain:
725 auto &object = getObject(insn.word(2));
726 auto &type = getType(insn.word(1));
727 auto &base = getObject(insn.word(3));
728 routine->createLvalue(insn.word(2), type.sizeInComponents); // TODO: this should be an ssavalue!
729 auto &pointerBase = getObject(object.pointerBase);
730 assert(type.sizeInComponents == 1);
731 assert(base.pointerBase == object.pointerBase);
733 if (pointerBase.storageClass == spv::StorageClassImage ||
734 pointerBase.storageClass == spv::StorageClassUniform ||
735 pointerBase.storageClass == spv::StorageClassUniformConstant)
737 UNIMPLEMENTED("Descriptor-backed OpAccessChain not yet implemented");
740 auto & dst = routine->getValue(insn.word(2));
741 dst[0] = As<Float4>(WalkAccessChain(insn.word(3), insn.wordCount() - 4, insn.wordPointer(4), routine));
746 auto &object = getObject(insn.word(2));
747 auto &pointer = getObject(insn.word(1));
748 auto &pointerBase = getObject(pointer.pointerBase);
750 if (pointerBase.storageClass == spv::StorageClassImage ||
751 pointerBase.storageClass == spv::StorageClassUniform ||
752 pointerBase.storageClass == spv::StorageClassUniformConstant)
754 UNIMPLEMENTED("Descriptor-backed store not yet implemented");
757 SpirvRoutine::Value& ptrBase = routine->getValue(pointer.pointerBase);
758 auto & src = routine->getValue(insn.word(2));;
760 if (pointer.kind == Object::Kind::Value)
762 auto offsets = As<Int4>(routine->getValue(insn.word(1)));
763 for (auto i = 0u; i < object.sizeInComponents; i++)
766 for (int j = 0; j < 4; j++)
768 auto dst = ptrBase[Int(i) + Extract(offsets, j)];
769 dst = Insert(dst, Extract(src[i], j), j);
775 // no divergent offsets
776 for (auto i = 0u; i < object.sizeInComponents; i++)
784 printf("emit: ignoring opcode %d\n", insn.opcode());