[TEST] Return the previous geometry shader passthrough handling

This commit is contained in:
CamilleLaVey
2026-08-18 16:25:31 -04:00
parent 809a61f600
commit b9c28ef6a1
4 changed files with 87 additions and 104 deletions
@@ -169,36 +169,11 @@ std::map<IR::Attribute, IR::Attribute> GenerateLegacyToGenericMappings(
return mapping;
}
struct PassthroughVertices {
u32 count;
u32 first;
u32 stride;
};
PassthroughVertices GetPassthroughVertices(InputTopology input_topology) {
switch (input_topology) {
case InputTopology::Points:
return {1, 0, 1};
case InputTopology::Lines:
return {2, 0, 1};
case InputTopology::LinesAdjacency:
return {2, 1, 1};
case InputTopology::Triangles:
return {3, 0, 1};
case InputTopology::TrianglesAdjacency:
return {3, 0, 2};
}
return {3, 0, 1};
}
void EmitGeometryPassthrough(IR::IREmitter& ir, const IR::Program& program,
const Shader::VaryingState& passthrough_mask,
bool passthrough_position,
std::optional<IR::Attribute> passthrough_layer_attr,
InputTopology input_topology) {
const PassthroughVertices vertices{GetPassthroughVertices(input_topology)};
for (u32 vertex = 0; vertex < vertices.count; vertex++) {
const u32 i = vertices.first + vertex * vertices.stride;
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)) {
@@ -233,16 +208,25 @@ void EmitGeometryPassthrough(IR::IREmitter& ir, const IR::Program& program,
ir.EndPrimitive(ir.Imm32(0));
}
void LowerGeometryPassthrough(const IR::Program& program, const HostTranslateInfo& host_info,
InputTopology input_topology) {
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), {},
input_topology);
program.info.passthrough.AnyComponent(IR::Attribute::PositionX), {});
}
}
}
@@ -251,8 +235,7 @@ void LowerGeometryPassthrough(const IR::Program& program, const HostTranslateInf
} // Anonymous namespace
IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool,
Environment& env, Flow::CFG& cfg, const HostTranslateInfo& host_info,
InputTopology input_topology) {
Environment& env, Flow::CFG& cfg, const HostTranslateInfo& host_info) {
HostTranslateInfo normalized_host_info{host_info};
normalized_host_info.ApplyDescriptorLimitPolicy();
@@ -281,9 +264,8 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
}
if (!normalized_host_info.support_geometry_shader_passthrough) {
program.output_vertices = GetPassthroughVertices(input_topology).count;
LowerGeometryPassthrough(program, normalized_host_info, input_topology);
program.is_geometry_passthrough = false;
program.output_vertices = GetOutputTopologyVertices(program.output_topology);
LowerGeometryPassthrough(program, normalized_host_info);
}
}
break;
@@ -432,12 +414,11 @@ IR::Program GenerateGeometryPassthrough(ObjectPool<IR::Inst>& inst_pool,
ObjectPool<IR::Block>& block_pool,
const HostTranslateInfo& host_info,
IR::Program& source_program,
Shader::OutputTopology output_topology,
InputTopology input_topology) {
Shader::OutputTopology output_topology) {
IR::Program program;
program.stage = Stage::Geometry;
program.output_topology = output_topology;
program.output_vertices = GetPassthroughVertices(input_topology).count;
program.output_vertices = GetOutputTopologyVertices(output_topology);
program.is_geometry_passthrough = false;
program.info.loads.mask = source_program.info.stores.mask;
@@ -452,7 +433,7 @@ IR::Program GenerateGeometryPassthrough(ObjectPool<IR::Inst>& inst_pool,
IR::IREmitter ir{*current_block};
EmitGeometryPassthrough(ir, program, program.info.stores, true,
source_program.info.emulated_layer, input_topology);
source_program.info.emulated_layer);
IR::Block* return_block{block_pool.Create(inst_pool)};
IR::IREmitter{*return_block}.Epilogue();
@@ -21,8 +21,7 @@ namespace Shader::Maxwell {
[[nodiscard]] IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool,
ObjectPool<IR::Block>& block_pool, Environment& env,
Flow::CFG& cfg, const HostTranslateInfo& host_info,
InputTopology input_topology);
Flow::CFG& cfg, const HostTranslateInfo& host_info);
[[nodiscard]] IR::Program MergeDualVertexPrograms(IR::Program& vertex_a, IR::Program& vertex_b,
Environment& env_vertex_b);
@@ -36,7 +35,6 @@ void ConvertLegacyToGeneric(IR::Program& program, const RuntimeInfo& runtime_inf
ObjectPool<IR::Block>& block_pool,
const HostTranslateInfo& host_info,
IR::Program& source_program,
Shader::OutputTopology output_topology,
InputTopology input_topology);
Shader::OutputTopology output_topology);
} // namespace Shader::Maxwell
@@ -72,25 +72,6 @@ Shader::OutputTopology MaxwellToOutputTopology(Maxwell::PrimitiveTopology topolo
}
}
Shader::InputTopology MaxwellToInputTopology(Maxwell::PrimitiveTopology topology) {
switch (topology) {
case Maxwell::PrimitiveTopology::Points:
return Shader::InputTopology::Points;
case Maxwell::PrimitiveTopology::Lines:
case Maxwell::PrimitiveTopology::LineLoop:
case Maxwell::PrimitiveTopology::LineStrip:
return Shader::InputTopology::Lines;
case Maxwell::PrimitiveTopology::LinesAdjacency:
case Maxwell::PrimitiveTopology::LineStripAdjacency:
return Shader::InputTopology::LinesAdjacency;
case Maxwell::PrimitiveTopology::TrianglesAdjacency:
case Maxwell::PrimitiveTopology::TriangleStripAdjacency:
return Shader::InputTopology::TrianglesAdjacency;
default:
return Shader::InputTopology::Triangles;
}
}
Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key,
const Shader::IR::Program& program,
const Shader::IR::Program* previous_program,
@@ -146,7 +127,33 @@ Shader::RuntimeInfo MakeRuntimeInfo(const GraphicsPipelineKey& key,
default:
break;
}
info.input_topology = MaxwellToInputTopology(key.gs_input_topology);
switch (key.gs_input_topology) {
case Maxwell::PrimitiveTopology::Points:
info.input_topology = Shader::InputTopology::Points;
break;
case Maxwell::PrimitiveTopology::Lines:
case Maxwell::PrimitiveTopology::LineLoop:
case Maxwell::PrimitiveTopology::LineStrip:
info.input_topology = Shader::InputTopology::Lines;
break;
case Maxwell::PrimitiveTopology::Triangles:
case Maxwell::PrimitiveTopology::TriangleStrip:
case Maxwell::PrimitiveTopology::TriangleFan:
case Maxwell::PrimitiveTopology::Quads:
case Maxwell::PrimitiveTopology::QuadStrip:
case Maxwell::PrimitiveTopology::Polygon:
case Maxwell::PrimitiveTopology::Patches:
info.input_topology = Shader::InputTopology::Triangles;
break;
case Maxwell::PrimitiveTopology::LinesAdjacency:
case Maxwell::PrimitiveTopology::LineStripAdjacency:
info.input_topology = Shader::InputTopology::LinesAdjacency;
break;
case Maxwell::PrimitiveTopology::TrianglesAdjacency:
case Maxwell::PrimitiveTopology::TriangleStripAdjacency:
info.input_topology = Shader::InputTopology::TrianglesAdjacency;
break;
}
info.glasm_use_storage_buffers = glasm_use_storage_buffers;
return info;
}
@@ -476,10 +483,8 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
&& index == u32(Maxwell::ShaderType::Geometry);
if (key.unique_hashes[index] == 0 && is_emulated_stage) {
auto topology = MaxwellToOutputTopology(key.gs_input_topology);
programs[index] =
GenerateGeometryPassthrough(pools.inst, pools.block, host_info,
*layer_source_program, topology,
MaxwellToInputTopology(key.gs_input_topology));
programs[index] = GenerateGeometryPassthrough(pools.inst, pools.block, host_info,
*layer_source_program, topology);
continue;
}
if (key.unique_hashes[index] == 0) {
@@ -497,15 +502,13 @@ std::unique_ptr<GraphicsPipeline> ShaderCache::CreateGraphicsPipeline(
if (!uses_vertex_a || index != 1) {
// Normal path
programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info,
MaxwellToInputTopology(key.gs_input_topology));
programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info);
total_storage_buffers += Shader::NumDescriptors(programs[index].info.storage_buffers_descriptors);
} else {
// VertexB path when VertexA is present.
auto& program_va{programs[0]};
auto program_vb{TranslateProgram(pools.inst, pools.block, env, cfg, host_info,
MaxwellToInputTopology(key.gs_input_topology))};
auto program_vb{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)};
total_storage_buffers += Shader::NumDescriptors(program_vb.info.storage_buffers_descriptors);
programs[index] = MergeDualVertexPrograms(program_va, program_vb, env);
}
@@ -594,8 +597,7 @@ std::unique_ptr<ComputePipeline> ShaderCache::CreateComputePipeline(
env.Dump(hash, key.unique_hash);
}
auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info,
Shader::InputTopology::Points)};
auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)};
const u32 num_storage_buffers{Shader::NumDescriptors(program.info.storage_buffers_descriptors)};
Shader::RuntimeInfo info;
info.glasm_use_storage_buffers = num_storage_buffers <= device.GetMaxGLASMStorageBufferBlocks();
@@ -152,25 +152,6 @@ Shader::AttributeType AttributeType(const FixedPipelineState& state, size_t inde
return Shader::AttributeType::Disabled;
}
Shader::InputTopology MaxwellToInputTopology(Maxwell::PrimitiveTopology topology) {
switch (topology) {
case Maxwell::PrimitiveTopology::Points:
return Shader::InputTopology::Points;
case Maxwell::PrimitiveTopology::Lines:
case Maxwell::PrimitiveTopology::LineLoop:
case Maxwell::PrimitiveTopology::LineStrip:
return Shader::InputTopology::Lines;
case Maxwell::PrimitiveTopology::LinesAdjacency:
case Maxwell::PrimitiveTopology::LineStripAdjacency:
return Shader::InputTopology::LinesAdjacency;
case Maxwell::PrimitiveTopology::TrianglesAdjacency:
case Maxwell::PrimitiveTopology::TriangleStripAdjacency:
return Shader::InputTopology::TrianglesAdjacency;
default:
return Shader::InputTopology::Triangles;
}
}
Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> programs,
const GraphicsPipelineCacheKey& key,
const Shader::IR::Program& program,
@@ -289,7 +270,33 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program
default:
break;
}
info.input_topology = MaxwellToInputTopology(key.state.topology);
switch (key.state.topology) {
case Maxwell::PrimitiveTopology::Points:
info.input_topology = Shader::InputTopology::Points;
break;
case Maxwell::PrimitiveTopology::Lines:
case Maxwell::PrimitiveTopology::LineLoop:
case Maxwell::PrimitiveTopology::LineStrip:
info.input_topology = Shader::InputTopology::Lines;
break;
case Maxwell::PrimitiveTopology::Triangles:
case Maxwell::PrimitiveTopology::TriangleStrip:
case Maxwell::PrimitiveTopology::TriangleFan:
case Maxwell::PrimitiveTopology::Quads:
case Maxwell::PrimitiveTopology::QuadStrip:
case Maxwell::PrimitiveTopology::Polygon:
case Maxwell::PrimitiveTopology::Patches:
info.input_topology = Shader::InputTopology::Triangles;
break;
case Maxwell::PrimitiveTopology::LinesAdjacency:
case Maxwell::PrimitiveTopology::LineStripAdjacency:
info.input_topology = Shader::InputTopology::LinesAdjacency;
break;
case Maxwell::PrimitiveTopology::TrianglesAdjacency:
case Maxwell::PrimitiveTopology::TriangleStripAdjacency:
info.input_topology = Shader::InputTopology::TrianglesAdjacency;
break;
}
info.force_early_z = key.state.early_z != 0;
info.y_negate = key.state.y_negate != 0;
return info;
@@ -786,10 +793,8 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
index == static_cast<u32>(Maxwell::ShaderType::Geometry);
if (key.unique_hashes[index] == 0 && is_emulated_stage) {
auto topology = MaxwellToOutputTopology(key.state.topology);
programs[index] =
GenerateGeometryPassthrough(pools.inst, pools.block, host_info,
*layer_source_program, topology,
MaxwellToInputTopology(key.state.topology));
programs[index] = GenerateGeometryPassthrough(pools.inst, pools.block, host_info,
*layer_source_program, topology);
continue;
}
if (key.unique_hashes[index] == 0) {
@@ -802,13 +807,11 @@ std::unique_ptr<GraphicsPipeline> PipelineCache::CreateGraphicsPipeline(
Shader::Maxwell::Flow::CFG cfg(env, pools.flow_block, cfg_offset, index == 0);
if (!uses_vertex_a || index != 1) {
// Normal path
programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info,
MaxwellToInputTopology(key.state.topology));
programs[index] = TranslateProgram(pools.inst, pools.block, env, cfg, host_info);
} else {
// VertexB path when VertexA is present.
auto& program_va{programs[0]};
auto program_vb{TranslateProgram(pools.inst, pools.block, env, cfg, host_info,
MaxwellToInputTopology(key.state.topology))};
auto program_vb{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)};
programs[index] = MergeDualVertexPrograms(program_va, program_vb, env);
}
@@ -954,8 +957,7 @@ std::unique_ptr<ComputePipeline> PipelineCache::CreateComputePipeline(
env.Dump(hash, key.unique_hash);
}
auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info,
Shader::InputTopology::Points)};
auto program{TranslateProgram(pools.inst, pools.block, env, cfg, host_info)};
const VkDriverIdKHR driver_id = device.GetDriverID();
const bool needs_shared_mem_clamp =
driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY ||