shader_recompiler: Better BFS search

This commit is contained in:
IndecisiveTurtle 2024-07-30 00:29:56 +03:00
parent 1638169bed
commit 7044cbcc99
2 changed files with 43 additions and 29 deletions

View File

@ -12,16 +12,17 @@
namespace Shader::IR { namespace Shader::IR {
template <typename Pred> template <typename Pred>
auto BreadthFirstSearch(const Value& value, Pred&& pred) auto BreadthFirstSearch(const Inst* inst, Pred&& pred)
-> std::invoke_result_t<Pred, const Inst*> { -> std::invoke_result_t<Pred, const Inst*> {
if (value.IsImmediate()) { // Most often case the instruction is the desired already.
// Nothing to do with immediates if (const std::optional result = pred(inst)) {
return std::nullopt; return result;
} }
// Breadth-first search visiting the right most arguments first // Breadth-first search visiting the right most arguments first
boost::container::small_vector<const Inst*, 2> visited; boost::container::small_vector<const Inst*, 2> visited;
std::queue<const Inst*> queue; std::queue<const Inst*> queue;
queue.push(value.InstRecursive()); queue.push(inst);
while (!queue.empty()) { while (!queue.empty()) {
// Pop one instruction from the queue // Pop one instruction from the queue
@ -49,4 +50,14 @@ auto BreadthFirstSearch(const Value& value, Pred&& pred)
return std::nullopt; return std::nullopt;
} }
template <typename Pred>
auto BreadthFirstSearch(const Value& value, Pred&& pred)
-> std::invoke_result_t<Pred, const Inst*> {
if (value.IsImmediate()) {
// Nothing to do with immediates
return std::nullopt;
}
return BreadthFirstSearch(value.InstRecursive(), pred);
}
} // namespace Shader::IR } // namespace Shader::IR

View File

@ -273,9 +273,18 @@ std::pair<const IR::Inst*, bool> TryDisableAnisoLod0(const IR::Inst* inst) {
} }
SharpLocation TrackSharp(const IR::Inst* inst) { SharpLocation TrackSharp(const IR::Inst* inst) {
while (inst->GetOpcode() == IR::Opcode::Phi) { // Search until we find a potential sharp source.
inst = inst->Arg(0).InstRecursive(); const auto pred0 = [](const IR::Inst* inst) -> std::optional<const IR::Inst*> {
} 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) { if (inst->GetOpcode() == IR::Opcode::GetUserData) {
return SharpLocation{ return SharpLocation{
.sgpr_base = u32(IR::ScalarReg::Max), .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(); const IR::Inst* spgpr_base = inst->Arg(0).InstRecursive();
// Retrieve SGPR pair that holds sbase // Retrieve SGPR pair that holds sbase
const auto pred = [](const IR::Inst* inst) -> std::optional<IR::ScalarReg> { const auto pred1 = [](const IR::Inst* inst) -> std::optional<IR::ScalarReg> {
if (inst->GetOpcode() == IR::Opcode::GetUserData) { if (inst->GetOpcode() == IR::Opcode::GetUserData) {
return inst->Arg(0).ScalarReg(); return inst->Arg(0).ScalarReg();
} }
return std::nullopt; return std::nullopt;
}; };
const auto base0 = IR::BreadthFirstSearch(spgpr_base->Arg(0), pred); const auto base0 = IR::BreadthFirstSearch(spgpr_base->Arg(0), pred1);
const auto base1 = IR::BreadthFirstSearch(spgpr_base->Arg(1), pred); const auto base1 = IR::BreadthFirstSearch(spgpr_base->Arg(1), pred1);
ASSERT_MSG(base0 && base1, "Nested resource loads not supported"); ASSERT_MSG(base0 && base1, "Nested resource loads not supported");
// Return retrieved location. // 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) { void PatchImageInstruction(IR::Block& block, IR::Inst& inst, Info& info, Descriptors& descriptors) {
std::deque<IR::Inst*> insts{&inst}; const auto pred = [](const IR::Inst* inst) -> std::optional<const IR::Inst*> {
const auto& pred = [](auto opcode) -> bool { const auto opcode = inst->GetOpcode();
return (opcode == IR::Opcode::CompositeConstructU32x2 || // IMAGE_SAMPLE (image+sampler) if (opcode == IR::Opcode::CompositeConstructU32x2 || // IMAGE_SAMPLE (image+sampler)
opcode == IR::Opcode::ReadConst || // IMAGE_LOAD (image only) opcode == IR::Opcode::ReadConst || // IMAGE_LOAD (image only)
opcode == IR::Opcode::GetUserData); opcode == IR::Opcode::GetUserData) {
}; return inst;
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());
}
} }
insts.pop_front(); return std::nullopt;
} };
ASSERT(pred(producer->GetOpcode())); const auto result = IR::BreadthFirstSearch(&inst, pred);
auto [tsharp_handle, ssharp_handle] = [&] -> std::pair<IR::Inst*, IR::Inst*> { ASSERT_MSG(result, "Unable to find image sharp source");
const IR::Inst* producer = result.value();
auto [tsharp_handle, ssharp_handle] = [&] -> std::pair<const IR::Inst*, const IR::Inst*> {
if (producer->GetOpcode() == IR::Opcode::CompositeConstructU32x2) { if (producer->GetOpcode() == IR::Opcode::CompositeConstructU32x2) {
return std::make_pair(producer->Arg(0).InstRecursive(), return std::make_pair(producer->Arg(0).InstRecursive(),
producer->Arg(1).InstRecursive()); producer->Arg(1).InstRecursive());