summaryrefslogtreecommitdiffstats
path: root/src/shader_recompiler/ir_opt
diff options
context:
space:
mode:
Diffstat (limited to 'src/shader_recompiler/ir_opt')
-rw-r--r--src/shader_recompiler/ir_opt/passes.h1
-rw-r--r--src/shader_recompiler/ir_opt/position_pass.cpp77
2 files changed, 78 insertions, 0 deletions
diff --git a/src/shader_recompiler/ir_opt/passes.h b/src/shader_recompiler/ir_opt/passes.h
index 6ff8e4266..24f609d69 100644
--- a/src/shader_recompiler/ir_opt/passes.h
+++ b/src/shader_recompiler/ir_opt/passes.h
@@ -17,6 +17,7 @@ void LowerFp16ToFp32(IR::Program& program);
void LowerInt64ToInt32(IR::Program& program);
void RescalingPass(IR::Program& program);
void SsaRewritePass(IR::Program& program);
+void PositionPass(Environment& env, IR::Program& program);
void TexturePass(Environment& env, IR::Program& program);
void VerificationPass(const IR::Program& program);
diff --git a/src/shader_recompiler/ir_opt/position_pass.cpp b/src/shader_recompiler/ir_opt/position_pass.cpp
new file mode 100644
index 000000000..3c20b7189
--- /dev/null
+++ b/src/shader_recompiler/ir_opt/position_pass.cpp
@@ -0,0 +1,77 @@
+// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <boost/container/small_vector.hpp>
+
+#include "shader_recompiler/frontend/ir/basic_block.h"
+#include "shader_recompiler/frontend/ir/ir_emitter.h"
+#include "shader_recompiler/frontend/ir/value.h"
+#include "shader_recompiler/ir_opt/passes.h"
+
+namespace Shader::Optimization {
+
+namespace {
+struct PositionInst {
+ IR::Inst* inst;
+ IR::Block* block;
+ IR::Attribute attr;
+};
+using PositionInstVector = boost::container::small_vector<PositionInst, 24>;
+} // Anonymous namespace
+
+void PositionPass(Environment& env, IR::Program& program) {
+ if (env.ShaderStage() != Stage::VertexB || env.ReadViewportTransformState()) {
+ return;
+ }
+
+ Info& info{program.info};
+ info.uses_render_area = true;
+
+ PositionInstVector to_replace;
+ for (IR::Block* const block : program.post_order_blocks) {
+ for (IR::Inst& inst : block->Instructions()) {
+ switch (inst.GetOpcode()) {
+ case IR::Opcode::SetAttribute: {
+ const IR::Attribute attr{inst.Arg(0).Attribute()};
+ switch (attr) {
+ case IR::Attribute::PositionX:
+ case IR::Attribute::PositionY: {
+ to_replace.push_back(PositionInst{.inst = &inst, .block = block, .attr = attr});
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+
+ for (PositionInst& position_inst : to_replace) {
+ IR::IREmitter ir{*position_inst.block,
+ IR::Block::InstructionList::s_iterator_to(*position_inst.inst)};
+ const IR::F32 value(position_inst.inst->Arg(1));
+ const IR::F32F64 scale(ir.Imm32(2.f));
+ const IR::F32 negative_one{ir.Imm32(-1.f)};
+ switch (position_inst.attr) {
+ case IR::Attribute::PositionX: {
+ position_inst.inst->SetArg(
+ 1,
+ ir.FPFma(value, ir.FPMul(ir.FPRecip(ir.RenderAreaWidth()), scale), negative_one));
+ break;
+ }
+ case IR::Attribute::PositionY: {
+ position_inst.inst->SetArg(
+ 1,
+ ir.FPFma(value, ir.FPMul(ir.FPRecip(ir.RenderAreaHeight()), scale), negative_one));
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+} // namespace Shader::Optimization