Add support for SPIRV decorations
This works in a single pass, and supports both toplevel and member
decorations. Includes support for 5 new opcodes:
- OpDecorate introduces a single decoration for a toplevel id.
- OpMemberDecorate introduces a single decoration for a <id,
memberIndex> pair.
- OpDecorationGroup introduces a new value category which has no
representation downstream at all. This is safely implemented by
doing nothing at all [we don't need to be able to introspect later].
- OpGroupDecorate applies all decorations in a decoration group to each
of a list of other ids.
- OpGroupMemberDecorate applies all decorations in a decoration group to
each of a list of members (<id>, memberIndex pairs).
Bug: b/120799499
Change-Id: Iaea970b23348e70d57ddb96a4df0726cfb511e03
Reviewed-on: https://swiftshader-review.googlesource.com/c/23174
Tested-by: Chris Forbes <chrisforbes@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp
index 752df8f..8ae2d8d 100644
--- a/src/Pipeline/SpirvShader.cpp
+++ b/src/Pipeline/SpirvShader.cpp
@@ -37,6 +37,60 @@
ProcessExecutionMode(insn);
break;
+ case spv::OpDecorate:
+ {
+ auto targetId = insn.word(1);
+ decorations[targetId].Apply(
+ static_cast<spv::Decoration>(insn.word(2)),
+ insn.wordCount() > 3 ? insn.word(3) : 0);
+ break;
+ }
+
+ case spv::OpMemberDecorate:
+ {
+ auto targetId = insn.word(1);
+ auto memberIndex = insn.word(2);
+ auto &d = memberDecorations[targetId];
+ if (memberIndex >= d.size())
+ d.resize(memberIndex + 1); // on demand; exact size would require another pass...
+ d[memberIndex].Apply(
+ static_cast<spv::Decoration>(insn.word(3)),
+ insn.wordCount() > 4 ? insn.word(4) : 0);
+ break;
+ }
+
+ case spv::OpDecorationGroup:
+ // Nothing to do here. We don't need to record the definition of the group; we'll just have
+ // the bundle of decorations float around. If we were to ever walk the decorations directly,
+ // we might think about introducing this as a real Object.
+ break;
+
+ case spv::OpGroupDecorate:
+ {
+ auto const &srcDecorations = decorations[insn.word(1)];
+ for (auto i = 2u; i < insn.wordCount(); i++)
+ {
+ // remaining operands are targets to apply the group to.
+ decorations[insn.word(i)].Apply(srcDecorations);
+ }
+ break;
+ }
+
+ case spv::OpGroupMemberDecorate:
+ {
+ auto const &srcDecorations = decorations[insn.word(1)];
+ for (auto i = 2u; i < insn.wordCount(); i += 2)
+ {
+ // remaining operands are pairs of <id>, literal for members to apply to.
+ auto &d = memberDecorations[insn.word(i)];
+ auto memberIndex = insn.word(i + 1);
+ if (memberIndex >= d.size())
+ d.resize(memberIndex + 1); // on demand resize, see above...
+ d[memberIndex].Apply(srcDecorations);
+ }
+ break;
+ }
+
case spv::OpTypeVoid:
case spv::OpTypeBool:
case spv::OpTypeInt:
@@ -73,6 +127,17 @@
object.definition = insn;
object.storageClass = storageClass;
object.sizeInComponents = defs[typeId].sizeInComponents;
+
+ // Register builtins
+ auto &d = decorations[resultId];
+ if (d.HasBuiltIn && storageClass == spv::StorageClassInput)
+ {
+ inputBuiltins[d.BuiltIn] = resultId;
+ }
+ if (d.HasBuiltIn && storageClass == spv::StorageClassOutput)
+ {
+ outputBuiltins[d.BuiltIn] = resultId;
+ }
break;
}
@@ -170,4 +235,69 @@
UNIMPLEMENTED("Only types are supported");
}
}
-}
\ No newline at end of file
+
+ void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg)
+ {
+ switch (decoration)
+ {
+ case spv::DecorationLocation:
+ HasLocation = true;
+ Location = static_cast<int32_t>(arg);
+ break;
+ case spv::DecorationComponent:
+ HasComponent = true;
+ Component = arg;
+ break;
+ case spv::DecorationBuiltIn:
+ HasBuiltIn = true;
+ BuiltIn = static_cast<spv::BuiltIn>(arg);
+ break;
+ case spv::DecorationFlat:
+ Flat = true;
+ break;
+ case spv::DecorationNoPerspective:
+ Noperspective = true;
+ break;
+ case spv::DecorationCentroid:
+ Centroid = true;
+ break;
+ case spv::DecorationBlock:
+ Block = true;
+ break;
+ case spv::DecorationBufferBlock:
+ BufferBlock = true;
+ break;
+ default:
+ // Intentionally partial, there are many decorations we just don't care about.
+ break;
+ }
+ }
+
+ void SpirvShader::Decorations::Apply(const sw::SpirvShader::Decorations &src)
+ {
+ // Apply a decoration group to this set of decorations
+ if (src.HasBuiltIn)
+ {
+ HasBuiltIn = true;
+ BuiltIn = src.BuiltIn;
+ }
+
+ if (src.HasLocation)
+ {
+ HasLocation = true;
+ Location = src.Location;
+ }
+
+ if (src.HasComponent)
+ {
+ HasComponent = true;
+ Component = src.Component;
+ }
+
+ Flat |= src.Flat;
+ Noperspective |= src.Noperspective;
+ Centroid |= src.Centroid;
+ Block |= src.Block;
+ BufferBlock |= src.BufferBlock;
+ }
+}