diff options
Diffstat (limited to '')
-rw-r--r-- | src/shader_recompiler/ir_opt/passes.h | 1 | ||||
-rw-r--r-- | src/shader_recompiler/ir_opt/position_pass.cpp | 77 | ||||
-rw-r--r-- | src/shader_recompiler/ir_opt/texture_pass.cpp | 49 |
3 files changed, 127 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 diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp index e8be58357..9eff84a3d 100644 --- a/src/shader_recompiler/ir_opt/texture_pass.cpp +++ b/src/shader_recompiler/ir_opt/texture_pass.cpp @@ -7,6 +7,7 @@ #include <boost/container/small_vector.hpp> +#include "common/settings.h" #include "shader_recompiler/environment.h" #include "shader_recompiler/frontend/ir/basic_block.h" #include "shader_recompiler/frontend/ir/breadth_first_search.h" @@ -363,6 +364,14 @@ TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) { return env.ReadTextureType(lhs_raw | rhs_raw); } +TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAddr& cbuf) { + const u32 secondary_index{cbuf.has_secondary ? cbuf.secondary_index : cbuf.index}; + const u32 secondary_offset{cbuf.has_secondary ? cbuf.secondary_offset : cbuf.offset}; + const u32 lhs_raw{env.ReadCbufValue(cbuf.index, cbuf.offset)}; + const u32 rhs_raw{env.ReadCbufValue(secondary_index, secondary_offset)}; + return env.ReadTexturePixelFormat(lhs_raw | rhs_raw); +} + class Descriptors { public: explicit Descriptors(TextureBufferDescriptors& texture_buffer_descriptors_, @@ -451,6 +460,38 @@ void PatchImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) { ir.FPMul(IR::F32(ir.CompositeExtract(coord, 1)), ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 1)))))); } + +void PathTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_format) { + const auto it{IR::Block::InstructionList::s_iterator_to(inst)}; + IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; + auto get_max_value = [pixel_format]() -> float { + switch (pixel_format) { + case TexturePixelFormat::A8B8G8R8_SNORM: + case TexturePixelFormat::R8G8_SNORM: + case TexturePixelFormat::R8_SNORM: + return 1.f / std::numeric_limits<char>::max(); + case TexturePixelFormat::R16G16B16A16_SNORM: + case TexturePixelFormat::R16G16_SNORM: + case TexturePixelFormat::R16_SNORM: + return 1.f / std::numeric_limits<short>::max(); + default: + throw InvalidArgument("Invalid texture pixel format"); + } + }; + + const IR::Value new_inst{&*block.PrependNewInst(it, inst)}; + const IR::F32 x(ir.CompositeExtract(new_inst, 0)); + const IR::F32 y(ir.CompositeExtract(new_inst, 1)); + const IR::F32 z(ir.CompositeExtract(new_inst, 2)); + const IR::F32 w(ir.CompositeExtract(new_inst, 3)); + const IR::F16F32F64 max_value(ir.Imm32(get_max_value())); + const IR::Value converted = + ir.CompositeConstruct(ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(x)), max_value), + ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(y)), max_value), + ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(z)), max_value), + ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::S32>(w)), max_value)); + inst.ReplaceUsesWith(converted); +} } // Anonymous namespace void TexturePass(Environment& env, IR::Program& program) { @@ -597,6 +638,14 @@ void TexturePass(Environment& env, IR::Program& program) { } else { inst->SetArg(0, IR::Value{}); } + + if (Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::OpenGL && + inst->GetOpcode() == IR::Opcode::ImageFetch && flags.type == TextureType::Buffer) { + const auto pixel_format = ReadTexturePixelFormat(env, cbuf); + if (pixel_format != TexturePixelFormat::OTHER) { + PathTexelFetch(*texture_inst.block, *texture_inst.inst, pixel_format); + } + } } } |