position_pass.cpp 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <boost/container/small_vector.hpp>
  4. #include "shader_recompiler/frontend/ir/basic_block.h"
  5. #include "shader_recompiler/frontend/ir/ir_emitter.h"
  6. #include "shader_recompiler/frontend/ir/value.h"
  7. #include "shader_recompiler/ir_opt/passes.h"
  8. namespace Shader::Optimization {
  9. namespace {
  10. struct PositionInst {
  11. IR::Inst* inst;
  12. IR::Block* block;
  13. IR::Attribute attr;
  14. };
  15. using PositionInstVector = boost::container::small_vector<PositionInst, 24>;
  16. } // Anonymous namespace
  17. void PositionPass(Environment& env, IR::Program& program) {
  18. if (env.ShaderStage() != Stage::VertexB || env.ReadViewportTransformState()) {
  19. return;
  20. }
  21. Info& info{program.info};
  22. info.uses_render_area = true;
  23. PositionInstVector to_replace;
  24. for (IR::Block* const block : program.post_order_blocks) {
  25. for (IR::Inst& inst : block->Instructions()) {
  26. switch (inst.GetOpcode()) {
  27. case IR::Opcode::SetAttribute: {
  28. const IR::Attribute attr{inst.Arg(0).Attribute()};
  29. switch (attr) {
  30. case IR::Attribute::PositionX:
  31. case IR::Attribute::PositionY: {
  32. to_replace.push_back(PositionInst{.inst = &inst, .block = block, .attr = attr});
  33. break;
  34. }
  35. default:
  36. break;
  37. }
  38. break;
  39. }
  40. default:
  41. break;
  42. }
  43. }
  44. }
  45. for (PositionInst& position_inst : to_replace) {
  46. IR::IREmitter ir{*position_inst.block,
  47. IR::Block::InstructionList::s_iterator_to(*position_inst.inst)};
  48. const IR::F32 value(position_inst.inst->Arg(1));
  49. const IR::F32F64 scale(ir.Imm32(2.f));
  50. const IR::F32 negative_one{ir.Imm32(-1.f)};
  51. switch (position_inst.attr) {
  52. case IR::Attribute::PositionX: {
  53. position_inst.inst->SetArg(
  54. 1,
  55. ir.FPFma(value, ir.FPMul(ir.FPRecip(ir.RenderAreaWidth()), scale), negative_one));
  56. break;
  57. }
  58. case IR::Attribute::PositionY: {
  59. position_inst.inst->SetArg(
  60. 1,
  61. ir.FPFma(value, ir.FPMul(ir.FPRecip(ir.RenderAreaHeight()), scale), negative_one));
  62. break;
  63. }
  64. default:
  65. break;
  66. }
  67. }
  68. }
  69. } // namespace Shader::Optimization