summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/frontend/maxwell/translate_program.cpp
diff options
context:
space:
mode:
authorGravatar Billy Laws2022-12-31 23:19:10 +0000
committerGravatar Billy Laws2023-01-05 22:13:07 +0000
commit625a4af73afec1a45f5a8004b0933f5a3d414103 (patch)
treecf4cf586433733c4f614d1ae0edff8c157d5a9cc /src/shader_recompiler/frontend/maxwell/translate_program.cpp
parentVulkan, OpenGL: Hook up storage buffer alignment code (diff)
downloadyuzu-625a4af73afec1a45f5a8004b0933f5a3d414103.tar.gz
yuzu-625a4af73afec1a45f5a8004b0933f5a3d414103.tar.xz
yuzu-625a4af73afec1a45f5a8004b0933f5a3d414103.zip
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.
Diffstat (limited to 'src/shader_recompiler/frontend/maxwell/translate_program.cpp')
-rw-r--r--src/shader_recompiler/frontend/maxwell/translate_program.cpp106
1 files changed, 66 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(
171 } 171 }
172 return mapping; 172 return mapping;
173} 173}
174
175void EmitGeometryPassthrough(IR::IREmitter& ir, const IR::Program& program, const Shader::VaryingState &passthrough_mask, bool passthrough_position, std::optional<IR::Attribute> passthrough_layer_attr) {
176 for (u32 i = 0; i < program.output_vertices; i++) {
177 // Assign generics from input
178 for (u32 j = 0; j < 32; j++) {
179 if (!passthrough_mask.Generic(j)) {
180 continue;
181 }
182
183 const IR::Attribute attr = IR::Attribute::Generic0X + (j * 4);
184 ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0));
185 ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0));
186 ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0));
187 ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0));
188 }
189
190 if (passthrough_position) {
191 // Assign position from input
192 const IR::Attribute attr = IR::Attribute::PositionX;
193 ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0));
194 ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0));
195 ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0));
196 ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0));
197 }
198
199 if (passthrough_layer_attr) {
200 // Assign layer
201 ir.SetAttribute(IR::Attribute::Layer, ir.GetAttribute(*passthrough_layer_attr), ir.Imm32(0));
202 }
203
204 // Emit vertex
205 ir.EmitVertex(ir.Imm32(0));
206 }
207 ir.EndPrimitive(ir.Imm32(0));
208}
209
210u32 GetOutputTopologyVertices(OutputTopology output_topology) {
211 switch (output_topology) {
212 case OutputTopology::PointList:
213 return 1;
214 case OutputTopology::LineStrip:
215 return 2;
216 default:
217 return 3;
218 }
219}
220
221void LowerGeometryPassthrough(const IR::Program& program, const HostTranslateInfo& host_info) {
222 for (IR::Block *const block : program.blocks) {
223 for (IR::Inst &inst : block->Instructions()) {
224 if (inst.GetOpcode() == IR::Opcode::Epilogue) {
225 IR::IREmitter ir{*block, IR::Block::InstructionList::s_iterator_to(inst)};
226 EmitGeometryPassthrough(ir, program, program.info.passthrough, program.info.passthrough.AnyComponent(IR::Attribute::PositionX), {});
227 }
228 }
229 }
230}
231
174} // Anonymous namespace 232} // Anonymous namespace
175 233
176IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Block>& block_pool, 234IR::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
198 for (size_t i = 0; i < program.info.passthrough.mask.size(); ++i) { 256 for (size_t i = 0; i < program.info.passthrough.mask.size(); ++i) {
199 program.info.passthrough.mask[i] = ((mask[i / 32] >> (i % 32)) & 1) == 0; 257 program.info.passthrough.mask[i] = ((mask[i / 32] >> (i % 32)) & 1) == 0;
200 } 258 }
259
260 if (!host_info.support_geometry_shader_passthrough) {
261 program.output_vertices = GetOutputTopologyVertices(program.output_topology);
262 LowerGeometryPassthrough(program, host_info);
263 }
201 } 264 }
202 break; 265 break;
203 } 266 }
@@ -342,17 +405,8 @@ IR::Program GenerateGeometryPassthrough(ObjectPool<IR::Inst>& inst_pool,
342 IR::Program program; 405 IR::Program program;
343 program.stage = Stage::Geometry; 406 program.stage = Stage::Geometry;
344 program.output_topology = output_topology; 407 program.output_topology = output_topology;
345 switch (output_topology) { 408 program.output_vertices = GetOutputTopologyVertices(output_topology);
346 case OutputTopology::PointList: 409
347 program.output_vertices = 1;
348 break;
349 case OutputTopology::LineStrip:
350 program.output_vertices = 2;
351 break;
352 default:
353 program.output_vertices = 3;
354 break;
355 }
356 410
357 program.is_geometry_passthrough = false; 411 program.is_geometry_passthrough = false;
358 program.info.loads.mask = source_program.info.stores.mask; 412 program.info.loads.mask = source_program.info.stores.mask;
@@ -366,35 +420,7 @@ IR::Program GenerateGeometryPassthrough(ObjectPool<IR::Inst>& inst_pool,
366 node.data.block = current_block; 420 node.data.block = current_block;
367 421
368 IR::IREmitter ir{*current_block}; 422 IR::IREmitter ir{*current_block};
369 for (u32 i = 0; i < program.output_vertices; i++) { 423 EmitGeometryPassthrough(ir, program, program.info.stores, true, source_program.info.emulated_layer);
370 // Assign generics from input
371 for (u32 j = 0; j < 32; j++) {
372 if (!program.info.stores.Generic(j)) {
373 continue;
374 }
375
376 const IR::Attribute attr = IR::Attribute::Generic0X + (j * 4);
377 ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0));
378 ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0));
379 ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0));
380 ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0));
381 }
382
383 // Assign position from input
384 const IR::Attribute attr = IR::Attribute::PositionX;
385 ir.SetAttribute(attr + 0, ir.GetAttribute(attr + 0, ir.Imm32(i)), ir.Imm32(0));
386 ir.SetAttribute(attr + 1, ir.GetAttribute(attr + 1, ir.Imm32(i)), ir.Imm32(0));
387 ir.SetAttribute(attr + 2, ir.GetAttribute(attr + 2, ir.Imm32(i)), ir.Imm32(0));
388 ir.SetAttribute(attr + 3, ir.GetAttribute(attr + 3, ir.Imm32(i)), ir.Imm32(0));
389
390 // Assign layer
391 ir.SetAttribute(IR::Attribute::Layer, ir.GetAttribute(source_program.info.emulated_layer),
392 ir.Imm32(0));
393
394 // Emit vertex
395 ir.EmitVertex(ir.Imm32(0));
396 }
397 ir.EndPrimitive(ir.Imm32(0));
398 424
399 IR::Block* return_block{block_pool.Create(inst_pool)}; 425 IR::Block* return_block{block_pool.Create(inst_pool)};
400 IR::IREmitter{*return_block}.Epilogue(); 426 IR::IREmitter{*return_block}.Epilogue();