From a92fa1f0f160d28cc166bbbeccd7d3b2a6581190 Mon Sep 17 00:00:00 2001 From: Forrest Keller Date: Fri, 30 Jan 2026 03:42:27 -0600 Subject: [PATCH] Fixed issue with the rebase --- src/shader_recompiler/ir_opt/texture_pass.cpp | 152 ++++++++++-------- 1 file changed, 89 insertions(+), 63 deletions(-) diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp index 7723879f68..2ebbaebbcc 100644 --- a/src/shader_recompiler/ir_opt/texture_pass.cpp +++ b/src/shader_recompiler/ir_opt/texture_pass.cpp @@ -22,18 +22,6 @@ namespace Shader::Optimization { namespace { -struct ConstBufferAddr { - u32 index; - u32 offset; - u32 shift_left; - u32 secondary_index; - u32 secondary_offset; - u32 secondary_shift_left; - IR::U32 dynamic_offset; - u32 count; - bool has_secondary; -}; - struct TextureInst { ConstBufferAddr cbuf; IR::Inst* inst; @@ -180,25 +168,58 @@ bool IsTextureInstruction(const IR::Inst& inst) { return IndexedInstruction(inst) != IR::Opcode::Void; } +// Per-pass caches + +static inline u32 ReadCbufCached(Environment& env, u32 index, u32 offset) { + const CbufWordKey k{index, offset}; + if (auto it = env.cbuf_word_cache.find(k); it != env.cbuf_word_cache.end()) return it->second; + const u32 v = env.ReadCbufValue(index, offset); + env.cbuf_word_cache.emplace(k, v); + return v; +} + +static inline u32 GetTextureHandleCached(Environment& env, const ConstBufferAddr& cbuf) { + const u32 sec_idx = cbuf.has_secondary ? cbuf.secondary_index : cbuf.index; + const u32 sec_off = cbuf.has_secondary ? cbuf.secondary_offset : cbuf.offset; + const HandleKey hk{cbuf.index, cbuf.offset, cbuf.shift_left, + sec_idx, sec_off, cbuf.secondary_shift_left, cbuf.has_secondary}; + if (auto it = env.handle_cache.find(hk); it != env.handle_cache.end()) return it->second; + + const u32 lhs = ReadCbufCached(env, cbuf.index, cbuf.offset) << cbuf.shift_left; + const u32 rhs = ReadCbufCached(env, sec_idx, sec_off) << cbuf.secondary_shift_left; + const u32 handle = lhs | rhs; + env.handle_cache.emplace(hk, handle); + return handle; +} + +// Cached variants of existing helpers +static inline TextureType ReadTextureTypeCached(Environment& env, const ConstBufferAddr& cbuf) { + return env.ReadTextureType(GetTextureHandleCached(env, cbuf)); +} +static inline TexturePixelFormat ReadTexturePixelFormatCached(Environment& env, + const ConstBufferAddr& cbuf) { + return env.ReadTexturePixelFormat(GetTextureHandleCached(env, cbuf)); +} +static inline bool IsTexturePixelFormatIntegerCached(Environment& env, + const ConstBufferAddr& cbuf) { + return env.IsTexturePixelFormatInteger(GetTextureHandleCached(env, cbuf)); +} + +std::optional Track(const IR::Value& value, Environment& env); +static inline std::optional TrackCached(const IR::Value& v, Environment& env) { + if (const IR::Inst* key = v.InstRecursive()) { + if (auto it = env.track_cache.find(key); it != env.track_cache.end()) return it->second; + auto found = Track(v, env); + if (found) env.track_cache.emplace(key, *found); + return found; + } + return Track(v, env); +} + std::optional TryGetConstBuffer(const IR::Inst* inst, Environment& env); std::optional Track(const IR::Value& value, Environment& env) { - return IR::BreadthFirstSearch( - value, [&env](const IR::Inst* inst) -> std::optional { - const auto opcode = inst->GetOpcode(); - - // I feel like Phi is already detected and handled but its here anyway - if (opcode == IR::Opcode::Phi) { - for (size_t i = 0; i < inst->NumArgs(); ++i) { - if (auto result = Track(inst->Arg(i), env)) { - return result; - } - } - return std::nullopt; - } - - return TryGetConstBuffer(inst, env); - }); + return IR::BreadthFirstSearch(value, [&env](const IR::Inst* inst) { return TryGetConstBuffer(inst, env); }); } std::optional TryGetConstant(IR::Value& value, Environment& env) { @@ -245,20 +266,20 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme LOG_DEBUG(Render_Vulkan, "TryGetConstBuffer: Unhandled opcode {}", static_cast(opcode)); return std::nullopt; case IR::Opcode::Identity: - return Track(inst->Arg(0), env); + return TrackCached(inst->Arg(0), env); case IR::Opcode::INeg32: case IR::Opcode::INeg64: - return Track(inst->Arg(0), env); + return TrackCached(inst->Arg(0), env); case IR::Opcode::BitCastU16F16: case IR::Opcode::BitCastF16U16: case IR::Opcode::BitCastU32F32: case IR::Opcode::BitCastF32U32: case IR::Opcode::BitCastU64F64: case IR::Opcode::BitCastF64U64: - return Track(inst->Arg(0), env); + return TrackCached(inst->Arg(0), env); case IR::Opcode::ConvertU32U64: case IR::Opcode::ConvertU64U32: - return Track(inst->Arg(0), env); + return TrackCached(inst->Arg(0), env); case IR::Opcode::SelectU1: case IR::Opcode::SelectU8: case IR::Opcode::SelectU16: @@ -267,10 +288,10 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme case IR::Opcode::SelectF16: case IR::Opcode::SelectF32: case IR::Opcode::SelectF64: { - if (auto result = Track(inst->Arg(1), env)) { + if (auto result = TrackCached(inst->Arg(1), env)) { return result; } - if (auto result = Track(inst->Arg(2), env)) { + if (auto result = TrackCached(inst->Arg(2), env)) { return result; } LOG_DEBUG(Render_Vulkan, "Select operation failed both branches"); @@ -281,22 +302,22 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme const IR::Value op2{inst->Arg(1)}; if (op2.IsImmediate()) { - if (auto res = Track(op1, env)) { + if (auto res = TrackCached(op1, env)) { res->offset += op2.U32(); return res; } } if (op1.IsImmediate()) { - if (auto res = Track(op2, env)) { + if (auto res = TrackCached(op2, env)) { res->offset += op1.U32(); return res; } } - if (auto result = Track(op1, env)) { + if (auto result = TrackCached(op1, env)) { return result; } - if (auto result = Track(op2, env)) { + if (auto result = TrackCached(op2, env)) { return result; } return std::nullopt; @@ -306,22 +327,22 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme const IR::Value op2{inst->Arg(1)}; if (op2.IsImmediate()) { - if (auto res = Track(op1, env)) { + if (auto res = TrackCached(op1, env)) { res->offset += static_cast(op2.U64()); return res; } } if (op1.IsImmediate()) { - if (auto res = Track(op2, env)) { + if (auto res = TrackCached(op2, env)) { res->offset += static_cast(op1.U64()); return res; } } - if (auto result = Track(op1, env)) { + if (auto result = TrackCached(op1, env)) { return result; } - if (auto result = Track(op2, env)) { + if (auto result = TrackCached(op2, env)) { return result; } return std::nullopt; @@ -331,13 +352,13 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme const IR::Value op2{inst->Arg(1)}; if (op2.IsImmediate()) { - if (auto res = Track(op1, env)) { + if (auto res = TrackCached(op1, env)) { res->offset -= op2.U32(); return res; } } - if (auto result = Track(op1, env)) { + if (auto result = TrackCached(op1, env)) { return result; } return std::nullopt; @@ -348,13 +369,13 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme const IR::Value op2{inst->Arg(1)}; if (op2.IsImmediate()) { - if (auto res = Track(op1, env)) { + if (auto res = TrackCached(op1, env)) { res->offset -= static_cast(op2.U64()); return res; } } - if (auto result = Track(op1, env)) { + if (auto result = TrackCached(op1, env)) { return result; } return std::nullopt; @@ -363,7 +384,7 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme case IR::Opcode::ShiftRightLogical64: { const IR::Value base{inst->Arg(0)}; const IR::Value shift{inst->Arg(1)}; - if (auto res = Track(base, env)) { + if (auto res = TrackCached(base, env)) { if (shift.IsImmediate()) { res->offset += (shift.U32() / 8); } @@ -379,7 +400,7 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme const IR::Value base{inst->Arg(0)}; const IR::Value offset{inst->Arg(1)}; - if (auto res = Track(base, env)) { + if (auto res = TrackCached(base, env)) { if (offset.IsImmediate()) { const u32 total_bits = offset.U32(); res->offset += (total_bits / 8); @@ -396,8 +417,8 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme } IR::Inst* const composite_inst{composite.InstRecursive()}; if (composite_inst->GetOpcode() == IR::Opcode::CompositeConstructU32x2) { - std::optional lhs{Track(composite_inst->Arg(0), env)}; - std::optional rhs{Track(composite_inst->Arg(1), env)}; + std::optional lhs{TrackCached(composite_inst->Arg(0), env)}; + std::optional rhs{TrackCached(composite_inst->Arg(1), env)}; if (!lhs || !rhs) { return std::nullopt; } @@ -422,12 +443,12 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme return std::nullopt; } case IR::Opcode::UnpackUint2x32: - return Track(inst->Arg(0), env); + return TrackCached(inst->Arg(0), env); case IR::Opcode::CompositeConstructU32x2: - if (auto result = Track(inst->Arg(0), env)) { + if (auto result = TrackCached(inst->Arg(0), env)) { return result; } - if (auto result = Track(inst->Arg(1), env)) { + if (auto result = TrackCached(inst->Arg(1), env)) { return result; } return std::nullopt; @@ -436,7 +457,7 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme const IR::Value composite{inst->Arg(0)}; const IR::Value index_val{inst->Arg(1)}; - if (auto res = Track(composite, env)) { + if (auto res = TrackCached(composite, env)) { if (index_val.IsImmediate()) { res->offset += index_val.U32() * 4; } @@ -445,8 +466,8 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme return std::nullopt; } case IR::Opcode::BitwiseOr32: { - std::optional lhs{Track(inst->Arg(0), env)}; - std::optional rhs{Track(inst->Arg(1), env)}; + std::optional lhs{TrackCached(inst->Arg(0), env)}; + std::optional rhs{TrackCached(inst->Arg(1), env)}; if (!lhs || !rhs) { return std::nullopt; } @@ -489,7 +510,7 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme if (!shift.IsImmediate()) { return std::nullopt; } - std::optional lhs{Track(inst->Arg(0), env)}; + std::optional lhs{TrackCached(inst->Arg(0), env)}; if (lhs) { lhs->shift_left = shift.U32(); } @@ -517,7 +538,7 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme return std::nullopt; } while (false); } - std::optional lhs{Track(op1, env)}; + std::optional lhs{TrackCached(op1, env)}; if (lhs) { if (op2.IsImmediate()) { lhs->shift_left = static_cast(std::countr_zero(op2.U32())); @@ -526,10 +547,10 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme return lhs; } case IR::Opcode::BitwiseXor32: { - if (auto result = Track(inst->Arg(0), env)) { + if (auto result = TrackCached(inst->Arg(0), env)) { return result; } - if (auto result = Track(inst->Arg(1), env)) { + if (auto result = TrackCached(inst->Arg(1), env)) { return result; } return std::nullopt; @@ -539,13 +560,13 @@ std::optional TryGetConstBuffer(const IR::Inst* inst, Environme const IR::Value op2{inst->Arg(1)}; if (op2.IsImmediate()) { - if (auto res = Track(op1, env)) { + if (auto res = TrackCached(op1, env)) { res->offset *= op2.U32(); return res; } } if (op1.IsImmediate()) { - if (auto res = Track(op2, env)) { + if (auto res = TrackCached(op2, env)) { res->offset *= op1.U32(); return res; } @@ -785,7 +806,7 @@ TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) { LOG_DEBUG(Render_Vulkan, "=== MakeInst: BINDLESS {} (stage: {}) ===", static_cast(opcode), static_cast(env.ShaderStage())); - const std::optional track_addr{Track(inst.Arg(0), env)}; + const std::optional track_addr{TrackCached(inst.Arg(0), env)}; if (!track_addr) { //throw NotImplementedException("Failed to track bindless texture constant buffer"); @@ -985,6 +1006,11 @@ void PatchTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_ } // Anonymous namespace void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info) { + // reset per-pass caches + env.cbuf_word_cache.clear(); + env.handle_cache.clear(); + env.track_cache.clear(); + TextureInstVector to_replace; for (IR::Block* const block : program.post_order_blocks) { for (IR::Inst& inst : block->Instructions()) {