diff --git a/src/shader_recompiler/ir/breadth_first_search.h b/src/shader_recompiler/ir/breadth_first_search.h index 21a34a903..223434098 100644 --- a/src/shader_recompiler/ir/breadth_first_search.h +++ b/src/shader_recompiler/ir/breadth_first_search.h @@ -12,16 +12,17 @@ namespace Shader::IR { template -auto BreadthFirstSearch(const Value& value, Pred&& pred) +auto BreadthFirstSearch(const Inst* inst, Pred&& pred) -> std::invoke_result_t { - if (value.IsImmediate()) { - // Nothing to do with immediates - return std::nullopt; + // Most often case the instruction is the desired already. + if (const std::optional result = pred(inst)) { + return result; } + // Breadth-first search visiting the right most arguments first boost::container::small_vector visited; std::queue queue; - queue.push(value.InstRecursive()); + queue.push(inst); while (!queue.empty()) { // Pop one instruction from the queue @@ -49,4 +50,14 @@ auto BreadthFirstSearch(const Value& value, Pred&& pred) return std::nullopt; } +template +auto BreadthFirstSearch(const Value& value, Pred&& pred) + -> std::invoke_result_t { + if (value.IsImmediate()) { + // Nothing to do with immediates + return std::nullopt; + } + return BreadthFirstSearch(value.InstRecursive(), pred); +} + } // namespace Shader::IR diff --git a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp index 6526ece62..1871243fa 100644 --- a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp +++ b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp @@ -273,9 +273,18 @@ std::pair TryDisableAnisoLod0(const IR::Inst* inst) { } SharpLocation TrackSharp(const IR::Inst* inst) { - while (inst->GetOpcode() == IR::Opcode::Phi) { - inst = inst->Arg(0).InstRecursive(); - } + // Search until we find a potential sharp source. + const auto pred0 = [](const IR::Inst* inst) -> std::optional { + if (inst->GetOpcode() == IR::Opcode::GetUserData || + inst->GetOpcode() == IR::Opcode::ReadConst) { + return inst; + } + return std::nullopt; + }; + const auto result = IR::BreadthFirstSearch(inst, pred0); + ASSERT_MSG(result, "Unable to track sharp source"); + inst = result.value(); + // If its from user data not much else to do. if (inst->GetOpcode() == IR::Opcode::GetUserData) { return SharpLocation{ .sgpr_base = u32(IR::ScalarReg::Max), @@ -289,14 +298,14 @@ SharpLocation TrackSharp(const IR::Inst* inst) { const IR::Inst* spgpr_base = inst->Arg(0).InstRecursive(); // Retrieve SGPR pair that holds sbase - const auto pred = [](const IR::Inst* inst) -> std::optional { + const auto pred1 = [](const IR::Inst* inst) -> std::optional { if (inst->GetOpcode() == IR::Opcode::GetUserData) { return inst->Arg(0).ScalarReg(); } return std::nullopt; }; - const auto base0 = IR::BreadthFirstSearch(spgpr_base->Arg(0), pred); - const auto base1 = IR::BreadthFirstSearch(spgpr_base->Arg(1), pred); + const auto base0 = IR::BreadthFirstSearch(spgpr_base->Arg(0), pred1); + const auto base1 = IR::BreadthFirstSearch(spgpr_base->Arg(1), pred1); ASSERT_MSG(base0 && base1, "Nested resource loads not supported"); // Return retrieved location. @@ -456,25 +465,19 @@ IR::Value PatchCubeCoord(IR::IREmitter& ir, const IR::Value& s, const IR::Value& } void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descriptors& descriptors) { - std::deque insts{&inst}; - const auto& pred = [](auto opcode) -> bool { - return (opcode == IR::Opcode::CompositeConstructU32x2 || // IMAGE_SAMPLE (image+sampler) - opcode == IR::Opcode::ReadConst || // IMAGE_LOAD (image only) - opcode == IR::Opcode::GetUserData); - }; - - IR::Inst* producer{}; - while (!insts.empty() && (producer = insts.front(), !pred(producer->GetOpcode()))) { - for (auto arg_idx = 0u; arg_idx < producer->NumArgs(); ++arg_idx) { - const auto arg = producer->Arg(arg_idx); - if (arg.TryInstRecursive()) { - insts.push_back(arg.InstRecursive()); - } + const auto pred = [](const IR::Inst* inst) -> std::optional { + const auto opcode = inst->GetOpcode(); + if (opcode == IR::Opcode::CompositeConstructU32x2 || // IMAGE_SAMPLE (image+sampler) + opcode == IR::Opcode::ReadConst || // IMAGE_LOAD (image only) + opcode == IR::Opcode::GetUserData) { + return inst; } - insts.pop_front(); - } - ASSERT(pred(producer->GetOpcode())); - auto [tsharp_handle, ssharp_handle] = [&] -> std::pair { + return std::nullopt; + }; + const auto result = IR::BreadthFirstSearch(&inst, pred); + ASSERT_MSG(result, "Unable to find image sharp source"); + const IR::Inst* producer = result.value(); + auto [tsharp_handle, ssharp_handle] = [&] -> std::pair { if (producer->GetOpcode() == IR::Opcode::CompositeConstructU32x2) { return std::make_pair(producer->Arg(0).InstRecursive(), producer->Arg(1).InstRecursive());