diff options
| author | Billy Laws <blaws05@gmail.com> | 2022-12-31 23:19:10 +0000 | 
|---|---|---|
| committer | Billy Laws <blaws05@gmail.com> | 2023-01-05 22:13:07 +0000 | 
| commit | 625a4af73afec1a45f5a8004b0933f5a3d414103 (patch) | |
| tree | cf4cf586433733c4f614d1ae0edff8c157d5a9cc | |
| parent | 9e2997c4b6456031622602002924617690e32a13 (diff) | |
shader_recompiler: Add support for lowering geometry passthrough
Reuses most of the existing code for generating the gl_Layer passthrough. Fixes geometry in Nier: Automata on GPUs without HW passthrough support.
| -rw-r--r-- | src/shader_recompiler/frontend/maxwell/translate_program.cpp | 106 | ||||
| -rw-r--r-- | src/shader_recompiler/host_translate_info.h | 1 | 
2 files changed, 67 insertions, 40 deletions
| diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.cpp b/src/shader_recompiler/frontend/maxwell/translate_program.cpp index 89fced84c..4a0ccceb7 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.cpp +++ b/src/shader_recompiler/frontend/maxwell/translate_program.cpp @@ -171,6 +171,64 @@ std::map<IR::Attribute, IR::Attribute> GenerateLegacyToGenericMappings(      }      return mapping;  } + +void EmitGeometryPassthrough(IR::IREmitter& ir, const IR::Program& program, const Shader::VaryingState &passthrough_mask, bool passthrough_position, std::optional<IR::Attribute> passthrough_layer_attr) { +    for (u32 i = 0; i < program.output_vertices; i++) { +        // Assign generics from input +        for (u32 j = 0; j < 32; j++) { +            if (!passthrough_mask.Generic(j)) { +                continue; +            } + +            const IR::Attribute attr = IR::Attribute::Generic0X + (j * 4); +            ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0)); +            ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0)); +            ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0)); +            ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0)); +        } + +        if (passthrough_position) { +            // Assign position from input +            const IR::Attribute attr = IR::Attribute::PositionX; +            ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0)); +            ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0)); +            ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0)); +            ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0)); +        } + +        if (passthrough_layer_attr) { +            // Assign layer +            ir.SetAttribute(IR::Attribute::Layer, ir.GetAttribute(*passthrough_layer_attr), ir.Imm32(0)); +        } + +        // Emit vertex +        ir.EmitVertex(ir.Imm32(0)); +    } +    ir.EndPrimitive(ir.Imm32(0)); +} + +u32 GetOutputTopologyVertices(OutputTopology output_topology) { +    switch (output_topology) { +        case OutputTopology::PointList: +            return 1; +        case OutputTopology::LineStrip: +            return 2; +        default: +            return 3; +    } +} + +void LowerGeometryPassthrough(const IR::Program& program, const HostTranslateInfo& host_info) { +    for (IR::Block *const block : program.blocks) { +        for (IR::Inst &inst : block->Instructions()) { +            if (inst.GetOpcode() == IR::Opcode::Epilogue) { +                IR::IREmitter ir{*block, IR::Block::InstructionList::s_iterator_to(inst)}; +                EmitGeometryPassthrough(ir, program, program.info.passthrough, program.info.passthrough.AnyComponent(IR::Attribute::PositionX), {}); +            } +        } +    } +} +  } // Anonymous namespace  IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool, @@ -198,6 +256,11 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo              for (size_t i = 0; i < program.info.passthrough.mask.size(); ++i) {                  program.info.passthrough.mask[i] = ((mask[i / 32] >> (i % 32)) & 1) == 0;              } + +            if (!host_info.support_geometry_shader_passthrough) { +                program.output_vertices = GetOutputTopologyVertices(program.output_topology); +                LowerGeometryPassthrough(program, host_info); +            }          }          break;      } @@ -342,17 +405,8 @@ IR::Program GenerateGeometryPassthrough(ObjectPool<IR::Inst>& inst_pool,      IR::Program program;      program.stage = Stage::Geometry;      program.output_topology = output_topology; -    switch (output_topology) { -    case OutputTopology::PointList: -        program.output_vertices = 1; -        break; -    case OutputTopology::LineStrip: -        program.output_vertices = 2; -        break; -    default: -        program.output_vertices = 3; -        break; -    } +    program.output_vertices = GetOutputTopologyVertices(output_topology); +      program.is_geometry_passthrough = false;      program.info.loads.mask = source_program.info.stores.mask; @@ -366,35 +420,7 @@ IR::Program GenerateGeometryPassthrough(ObjectPool<IR::Inst>& inst_pool,      node.data.block = current_block;      IR::IREmitter ir{*current_block}; -    for (u32 i = 0; i < program.output_vertices; i++) { -        // Assign generics from input -        for (u32 j = 0; j < 32; j++) { -            if (!program.info.stores.Generic(j)) { -                continue; -            } - -            const IR::Attribute attr = IR::Attribute::Generic0X + (j * 4); -            ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0)); -            ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0)); -            ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0)); -            ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0)); -        } - -        // Assign position from input -        const IR::Attribute attr = IR::Attribute::PositionX; -        ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0)); -        ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0)); -        ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0)); -        ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0)); - -        // Assign layer -        ir.SetAttribute(IR::Attribute::Layer, ir.GetAttribute(source_program.info.emulated_layer), -                        ir.Imm32(0)); - -        // Emit vertex -        ir.EmitVertex(ir.Imm32(0)); -    } -    ir.EndPrimitive(ir.Imm32(0)); +    EmitGeometryPassthrough(ir, program, program.info.stores, true, source_program.info.emulated_layer);      IR::Block* return_block{block_pool.Create(inst_pool)};      IR::IREmitter{*return_block}.Epilogue(); diff --git a/src/shader_recompiler/host_translate_info.h b/src/shader_recompiler/host_translate_info.h index 7df090124..dc402ee47 100644 --- a/src/shader_recompiler/host_translate_info.h +++ b/src/shader_recompiler/host_translate_info.h @@ -16,6 +16,7 @@ struct HostTranslateInfo {      bool support_snorm_render_buffer{};  ///< True when the device supports SNORM render buffers      bool support_viewport_index_layer{}; ///< True when the device supports gl_Layer in VS      u32 min_ssbo_alignment{};  ///< Minimum alignment supported by the device for SSBOs +    bool support_geometry_shader_passthrough{}; ///< True when the device supports geometry passthrough shaders  };  } // namespace Shader | 
