Templatize PopulateInterface & friends I need to also walk interface objects in shader prolog & epilog; will reuse this logic. Bug: b/124388146 Change-Id: Ida735f58aa1bc36d83e4a6ea3c16925a9c5656b0 Reviewed-on: https://swiftshader-review.googlesource.com/c/24808 Reviewed-by: Ben Clayton <bclayton@google.com> Reviewed-by: Nicolas Capens <nicolascapens@google.com> Tested-by: Chris Forbes <chrisforbes@google.com> Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
diff --git a/src/Pipeline/SpirvShader.cpp b/src/Pipeline/SpirvShader.cpp index ba86f30..86c1a20 100644 --- a/src/Pipeline/SpirvShader.cpp +++ b/src/Pipeline/SpirvShader.cpp
@@ -296,7 +296,19 @@ else { object.kind = Object::Kind::InterfaceVariable; - PopulateInterface(&userDefinedInterface, resultId); + VisitInterface(resultId, + [&userDefinedInterface](Decorations const &d, AttribType type) { + // Populate a single scalar slot in the interface from a collection of decorations and the intended component type. + auto scalarSlot = (d.Location << 2) | d.Component; + assert(scalarSlot >= 0 && + scalarSlot < static_cast<int32_t>(userDefinedInterface.size())); + + auto &slot = userDefinedInterface[scalarSlot]; + slot.Type = type; + slot.Flat = d.Flat; + slot.NoPerspective = d.NoPerspective; + slot.Centroid = d.Centroid; + }); } } @@ -391,20 +403,8 @@ } } - void SpirvShader::PopulateInterfaceSlot(std::vector<InterfaceComponent> *iface, Decorations const &d, AttribType type) - { - // Populate a single scalar slot in the interface from a collection of decorations and the intended component type. - auto scalarSlot = (d.Location << 2) | d.Component; - assert(scalarSlot >= 0 && scalarSlot < static_cast<int32_t>(iface->size())); - - auto &slot = (*iface)[scalarSlot]; - slot.Type = type; - slot.Flat = d.Flat; - slot.NoPerspective = d.NoPerspective; - slot.Centroid = d.Centroid; - } - - int SpirvShader::PopulateInterfaceInner(std::vector<InterfaceComponent> *iface, uint32_t id, Decorations d) + template<typename F> + int SpirvShader::VisitInterfaceInner(uint32_t id, Decorations d, F f) const { // Recursively walks variable definition and its type tree, taking into account // any explicit Location or Component decorations encountered; where explicit @@ -412,7 +412,9 @@ // Collected decorations are carried down toward the leaves and across // siblings; Effect of decorations intentionally does not flow back up the tree. // - // Returns the next available location. + // F is a functor to be called with the effective decoration set for every component. + // + // Returns the next available location, and calls f(). // This covers the rules in Vulkan 1.1 spec, 14.1.4 Location Assignment. @@ -422,29 +424,29 @@ switch (obj.definition.opcode()) { case spv::OpTypePointer: - return PopulateInterfaceInner(iface, obj.definition.word(3), d); + return VisitInterfaceInner<F>(obj.definition.word(3), d, f); case spv::OpTypeMatrix: for (auto i = 0u; i < obj.definition.word(3); i++, d.Location++) { // consumes same components of N consecutive locations - PopulateInterfaceInner(iface, obj.definition.word(2), d); + VisitInterfaceInner<F>(obj.definition.word(2), d, f); } return d.Location; case spv::OpTypeVector: for (auto i = 0u; i < obj.definition.word(3); i++, d.Component++) { // consumes N consecutive components in the same location - PopulateInterfaceInner(iface, obj.definition.word(2), d); + VisitInterfaceInner<F>(obj.definition.word(2), d, f); } return d.Location + 1; case spv::OpTypeFloat: - PopulateInterfaceSlot(iface, d, ATTRIBTYPE_FLOAT); + f(d, ATTRIBTYPE_FLOAT); return d.Location + 1; case spv::OpTypeInt: - PopulateInterfaceSlot(iface, d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT); + f(d, obj.definition.word(3) ? ATTRIBTYPE_INT : ATTRIBTYPE_UINT); return d.Location + 1; case spv::OpTypeBool: - PopulateInterfaceSlot(iface, d, ATTRIBTYPE_UINT); + f(d, ATTRIBTYPE_UINT); return d.Location + 1; case spv::OpTypeStruct: { @@ -452,7 +454,7 @@ for (auto i = 0u; i < obj.definition.wordCount() - 2; i++) { ApplyDecorationsForIdMember(&d, id, i); - d.Location = PopulateInterfaceInner(iface, obj.definition.word(i + 2), d); + d.Location = VisitInterfaceInner<F>(obj.definition.word(i + 2), d, f); d.Component = 0; // Implicit locations always have component=0 } return d.Location; @@ -462,7 +464,7 @@ auto arraySize = GetConstantInt(obj.definition.word(3)); for (auto i = 0u; i < arraySize; i++) { - d.Location = PopulateInterfaceInner(iface, obj.definition.word(2), d); + d.Location = VisitInterfaceInner<F>(obj.definition.word(2), d, f); } return d.Location; } @@ -472,15 +474,16 @@ } } - void SpirvShader::PopulateInterface(std::vector<InterfaceComponent> *iface, uint32_t id) + template<typename F> + void SpirvShader::VisitInterface(uint32_t id, F f) const { - // Walk a variable definition and populate the interface from it. + // Walk a variable definition and call f for each component in it. Decorations d{}; ApplyDecorationsForId(&d, id); auto def = getObject(id).definition; assert(def.opcode() == spv::OpVariable); - PopulateInterfaceInner(iface, def.word(1), d); + VisitInterfaceInner<F>(def.word(1), d, f); } void SpirvShader::Decorations::Apply(spv::Decoration decoration, uint32_t arg) @@ -564,7 +567,7 @@ } } - uint32_t SpirvShader::GetConstantInt(uint32_t id) + uint32_t SpirvShader::GetConstantInt(uint32_t id) const { // Slightly hackish access to constants very early in translation. // General consumption of constants by other instructions should @@ -572,7 +575,7 @@ // TODO: not encountered yet since we only use this for array sizes etc, // but is possible to construct integer constant 0 via OpConstantNull. - auto insn = defs[id].definition; + auto insn = getObject(id).definition; assert(insn.opcode() == spv::OpConstant); assert(getType(insn.word(1)).definition.opcode() == spv::OpTypeInt); return insn.word(3);