dual_vertex_pass.cpp 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <ranges>
  6. #include <tuple>
  7. #include <type_traits>
  8. #include "common/bit_cast.h"
  9. #include "common/bit_util.h"
  10. #include "shader_recompiler/exception.h"
  11. #include "shader_recompiler/frontend/ir/ir_emitter.h"
  12. #include "shader_recompiler/ir_opt/passes.h"
  13. namespace Shader::Optimization {
  14. void VertexATransformPass(IR::Program& program) {
  15. bool replaced_join{};
  16. bool eliminated_epilogue{};
  17. for (IR::Block* const block : program.post_order_blocks) {
  18. for (IR::Inst& inst : block->Instructions()) {
  19. switch (inst.GetOpcode()) {
  20. case IR::Opcode::Return:
  21. inst.ReplaceOpcode(IR::Opcode::Join);
  22. replaced_join = true;
  23. break;
  24. case IR::Opcode::Epilogue:
  25. inst.Invalidate();
  26. eliminated_epilogue = true;
  27. break;
  28. default:
  29. break;
  30. }
  31. if (replaced_join && eliminated_epilogue) {
  32. return;
  33. }
  34. }
  35. }
  36. }
  37. void VertexBTransformPass(IR::Program& program) {
  38. for (IR::Block* const block : program.post_order_blocks | std::views::reverse) {
  39. for (IR::Inst& inst : block->Instructions()) {
  40. if (inst.GetOpcode() == IR::Opcode::Prologue) {
  41. return inst.Invalidate();
  42. }
  43. }
  44. }
  45. }
  46. void DualVertexJoinPass(IR::Program& program) {
  47. const auto& blocks = program.blocks;
  48. s64 s = static_cast<s64>(blocks.size()) - 1;
  49. if (s < 1) {
  50. throw NotImplementedException("Dual Vertex Join pass failed, expected atleast 2 blocks!");
  51. }
  52. for (s64 index = 0; index < s; index++) {
  53. IR::Block* const current_block = blocks[index];
  54. IR::Block* const next_block = blocks[index + 1];
  55. for (IR::Inst& inst : current_block->Instructions()) {
  56. if (inst.GetOpcode() == IR::Opcode::Join) {
  57. IR::IREmitter ir{*current_block, IR::Block::InstructionList::s_iterator_to(inst)};
  58. ir.Branch(next_block);
  59. inst.Invalidate();
  60. // only 1 join should exist
  61. return;
  62. }
  63. }
  64. }
  65. throw NotImplementedException("Dual Vertex Join pass failed, no join present!");
  66. }
  67. } // namespace Shader::Optimization