diff --git a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp index c5bfe5796..778da149f 100644 --- a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp +++ b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp @@ -235,9 +235,12 @@ std::pair TryDisableAnisoLod0(const IR::Inst* inst) { return {prod2, true}; } -SharpLocation TrackSharp(const IR::Inst* inst, const Shader::Info& info) { +SharpLocation AttemptTrackSharp(const IR::Inst* inst, auto& visited_insts) { // Search until we find a potential sharp source. - const auto pred = [](const IR::Inst* inst) -> std::optional { + const auto pred = [&visited_insts](const IR::Inst* inst) -> std::optional { + if (std::ranges::find(visited_insts, inst) != visited_insts.end()) { + return std::nullopt; + } if (inst->GetOpcode() == IR::Opcode::GetUserData || inst->GetOpcode() == IR::Opcode::ReadConst) { return inst; @@ -247,6 +250,7 @@ SharpLocation TrackSharp(const IR::Inst* inst, const Shader::Info& info) { const auto result = IR::BreadthFirstSearch(inst, pred); ASSERT_MSG(result, "Unable to track sharp source"); inst = result.value(); + visited_insts.emplace_back(inst); if (inst->GetOpcode() == IR::Opcode::GetUserData) { return static_cast(inst->Arg(0).ScalarReg()); } else { @@ -256,6 +260,29 @@ SharpLocation TrackSharp(const IR::Inst* inst, const Shader::Info& info) { } } +/// Tracks a sharp with validation of the chosen data type. +template +std::pair TrackSharp(const IR::Inst* inst, const Info& info) { + boost::container::small_vector visited_insts{}; + while (true) { + const auto prev_size = visited_insts.size(); + const auto sharp = AttemptTrackSharp(inst, visited_insts); + if (const auto data = info.ReadUdSharp(sharp); data.Valid()) { + return std::make_pair(sharp, data); + } + if (prev_size == visited_insts.size()) { + // No change in visited instructions, we've run out of paths. + UNREACHABLE_MSG("Unable to find valid sharp."); + } + } +} + +/// Tracks a sharp without data validation. +SharpLocation TrackSharp(const IR::Inst* inst, const Info& info) { + boost::container::static_vector visited_insts{}; + return AttemptTrackSharp(inst, visited_insts); +} + s32 TryHandleInlineCbuf(IR::Inst& inst, Info& info, Descriptors& descriptors, AmdGpu::Buffer& cbuf) { @@ -293,8 +320,8 @@ void PatchBufferSharp(IR::Block& block, IR::Inst& inst, Info& info, Descriptors& if (binding = TryHandleInlineCbuf(inst, info, descriptors, buffer); binding == -1) { IR::Inst* handle = inst.Arg(0).InstRecursive(); IR::Inst* producer = handle->Arg(0).InstRecursive(); - const auto sharp = TrackSharp(producer, info); - buffer = info.ReadUdSharp(sharp); + SharpLocation sharp; + std::tie(sharp, buffer) = TrackSharp(producer, info); binding = descriptors.Add(BufferResource{ .sharp_idx = sharp, .used_types = BufferDataType(inst, buffer.GetNumberFmt()),