rescaling_pass.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/alignment.h"
  5. #include "common/settings.h"
  6. #include "shader_recompiler/environment.h"
  7. #include "shader_recompiler/frontend/ir/ir_emitter.h"
  8. #include "shader_recompiler/frontend/ir/modifiers.h"
  9. #include "shader_recompiler/frontend/ir/program.h"
  10. #include "shader_recompiler/frontend/ir/value.h"
  11. #include "shader_recompiler/ir_opt/passes.h"
  12. #include "shader_recompiler/shader_info.h"
  13. namespace Shader::Optimization {
  14. namespace {
  15. void PatchFragCoord(IR::Block& block, IR::Inst& inst) {
  16. IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
  17. const IR::F32 down_factor{ir.ResolutionDownFactor()};
  18. const IR::F32 frag_coord{ir.GetAttribute(inst.Arg(0).Attribute())};
  19. const IR::F32 downscaled_frag_coord{ir.FPMul(frag_coord, down_factor)};
  20. inst.ReplaceUsesWith(downscaled_frag_coord);
  21. }
  22. [[nodiscard]] IR::U32 Scale(IR::IREmitter& ir, const IR::U1& is_scaled, const IR::U32& value) {
  23. IR::U32 scaled_value{value};
  24. bool changed{};
  25. if (const u32 up_scale = Settings::values.resolution_info.up_scale; up_scale != 1) {
  26. scaled_value = ir.IMul(value, ir.Imm32(up_scale));
  27. changed = true;
  28. }
  29. if (const u32 down_shift = Settings::values.resolution_info.down_shift; down_shift != 0) {
  30. scaled_value = ir.ShiftRightArithmetic(value, ir.Imm32(down_shift));
  31. changed = true;
  32. }
  33. if (changed) {
  34. return IR::U32{ir.Select(is_scaled, scaled_value, value)};
  35. } else {
  36. return value;
  37. }
  38. }
  39. [[nodiscard]] IR::U32 DownScale(IR::IREmitter& ir, IR::U32 value) {
  40. if (const u32 down_shift = Settings::values.resolution_info.down_shift; down_shift != 0) {
  41. value = ir.ShiftLeftLogical(value, ir.Imm32(down_shift));
  42. }
  43. if (const u32 up_scale = Settings::values.resolution_info.up_scale; up_scale != 1) {
  44. value = ir.IDiv(value, ir.Imm32(up_scale));
  45. }
  46. return value;
  47. }
  48. void PatchImageQueryDimensions(IR::Block& block, IR::Inst& inst) {
  49. const auto it{IR::Block::InstructionList::s_iterator_to(inst)};
  50. IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
  51. const auto info{inst.Flags<IR::TextureInstInfo>()};
  52. switch (info.type) {
  53. case TextureType::Color1D:
  54. case TextureType::ColorArray1D: {
  55. const IR::Value new_inst{&*block.PrependNewInst(it, inst)};
  56. const IR::U32 width{DownScale(ir, IR::U32{ir.CompositeExtract(new_inst, 0)})};
  57. const IR::Value replacement{ir.CompositeConstruct(width, ir.CompositeExtract(new_inst, 1),
  58. ir.CompositeExtract(new_inst, 2),
  59. ir.CompositeExtract(new_inst, 3))};
  60. inst.ReplaceUsesWith(replacement);
  61. break;
  62. }
  63. case TextureType::Color2D:
  64. case TextureType::ColorArray2D: {
  65. const IR::Value new_inst{&*block.PrependNewInst(it, inst)};
  66. const IR::U32 width{DownScale(ir, IR::U32{ir.CompositeExtract(new_inst, 0)})};
  67. const IR::U32 height{DownScale(ir, IR::U32{ir.CompositeExtract(new_inst, 1)})};
  68. const IR::Value replacement{ir.CompositeConstruct(
  69. width, height, ir.CompositeExtract(new_inst, 2), ir.CompositeExtract(new_inst, 3))};
  70. inst.ReplaceUsesWith(replacement);
  71. break;
  72. }
  73. case TextureType::Color3D:
  74. case TextureType::ColorCube:
  75. case TextureType::ColorArrayCube:
  76. case TextureType::Buffer:
  77. // Nothing to patch here
  78. break;
  79. }
  80. }
  81. void ScaleIntegerCoord(IR::IREmitter& ir, IR::Inst& inst, const IR::U1& is_scaled) {
  82. const auto info{inst.Flags<IR::TextureInstInfo>()};
  83. const IR::Value coord{inst.Arg(1)};
  84. switch (info.type) {
  85. case TextureType::Color1D:
  86. inst.SetArg(1, Scale(ir, is_scaled, IR::U32{coord}));
  87. break;
  88. case TextureType::ColorArray1D: {
  89. const IR::U32 x{Scale(ir, is_scaled, IR::U32{ir.CompositeExtract(coord, 0)})};
  90. const IR::U32 y{ir.CompositeExtract(coord, 1)};
  91. inst.SetArg(1, ir.CompositeConstruct(x, y));
  92. break;
  93. }
  94. case TextureType::Color2D: {
  95. const IR::U32 x{Scale(ir, is_scaled, IR::U32{ir.CompositeExtract(coord, 0)})};
  96. const IR::U32 y{Scale(ir, is_scaled, IR::U32{ir.CompositeExtract(coord, 1)})};
  97. inst.SetArg(1, ir.CompositeConstruct(x, y));
  98. break;
  99. }
  100. case TextureType::ColorArray2D: {
  101. const IR::U32 x{Scale(ir, is_scaled, IR::U32{ir.CompositeExtract(coord, 0)})};
  102. const IR::U32 y{Scale(ir, is_scaled, IR::U32{ir.CompositeExtract(coord, 1)})};
  103. const IR::U32 z{ir.CompositeExtract(coord, 2)};
  104. inst.SetArg(1, ir.CompositeConstruct(x, y, z));
  105. break;
  106. }
  107. case TextureType::Color3D:
  108. case TextureType::ColorCube:
  109. case TextureType::ColorArrayCube:
  110. case TextureType::Buffer:
  111. // Nothing to patch here
  112. break;
  113. }
  114. }
  115. void PatchImageFetch(IR::Block& block, IR::Inst& inst) {
  116. IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
  117. const auto info{inst.Flags<IR::TextureInstInfo>()};
  118. const IR::U1 is_scaled{ir.IsTextureScaled(ir.Imm32(info.descriptor_index))};
  119. ScaleIntegerCoord(ir, inst, is_scaled);
  120. }
  121. void PatchImageRead(IR::Block& block, IR::Inst& inst) {
  122. IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
  123. const auto info{inst.Flags<IR::TextureInstInfo>()};
  124. // TODO: Scale conditionally
  125. const IR::U1 is_scaled{IR::Value{true}};
  126. ScaleIntegerCoord(ir, inst, is_scaled);
  127. }
  128. void Visit(const IR::Program& program, IR::Block& block, IR::Inst& inst) {
  129. const bool is_fragment_shader{program.stage == Stage::Fragment};
  130. switch (inst.GetOpcode()) {
  131. case IR::Opcode::GetAttribute: {
  132. const IR::Attribute attr{inst.Arg(0).Attribute()};
  133. switch (attr) {
  134. case IR::Attribute::PositionX:
  135. case IR::Attribute::PositionY:
  136. if (is_fragment_shader) {
  137. PatchFragCoord(block, inst);
  138. }
  139. break;
  140. default:
  141. break;
  142. }
  143. break;
  144. }
  145. case IR::Opcode::ImageQueryDimensions:
  146. PatchImageQueryDimensions(block, inst);
  147. break;
  148. case IR::Opcode::ImageFetch:
  149. PatchImageFetch(block, inst);
  150. break;
  151. case IR::Opcode::ImageRead:
  152. PatchImageRead(block, inst);
  153. break;
  154. default:
  155. break;
  156. }
  157. }
  158. } // Anonymous namespace
  159. void RescalingPass(IR::Program& program) {
  160. for (IR::Block* const block : program.post_order_blocks) {
  161. for (IR::Inst& inst : block->Instructions()) {
  162. Visit(program, *block, inst);
  163. }
  164. }
  165. }
  166. } // namespace Shader::Optimization