resource_tracking_pass: Perform BFS for sharp tracking

* The Witness triggered this
This commit is contained in:
IndecisiveTurtle 2024-07-06 02:26:44 +03:00
parent 1e842c01bf
commit 1b5a96e307
5 changed files with 72 additions and 15 deletions

View file

@ -1029,7 +1029,7 @@ s32 PS4_SYSV_ABI sceGnmInsertPushMarker(u32* cmdbuf, u32 size, const char* marke
if (cmdbuf && marker) {
const auto len = std::strlen(marker);
const u32 packet_size = ((len + 8) >> 2) + ((len + 0xc) >> 3);
const u32 packet_size = ((len + 8) >> 2) + ((len + 0xc) >> 3) * 2;
if (packet_size + 2 == size) {
auto* nop = reinterpret_cast<PM4CmdNop*>(cmdbuf);
nop->header =

View file

@ -396,6 +396,7 @@ void Translate(IR::Block* block, u32 block_base, std::span<const GcnInst> inst_l
case Opcode::IMAGE_SAMPLE_L:
case Opcode::IMAGE_SAMPLE_C_O:
case Opcode::IMAGE_SAMPLE_B:
case Opcode::IMAGE_SAMPLE_C_LZ_O:
translator.IMAGE_SAMPLE(inst);
break;
case Opcode::IMAGE_ATOMIC_ADD:

View file

@ -0,0 +1,52 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <optional>
#include <type_traits>
#include <boost/container/small_vector.hpp>
#include <queue>
#include "shader_recompiler/ir/value.h"
namespace Shader::IR {
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;
}
// Breadth-first search visiting the right most arguments first
boost::container::small_vector<const Inst*, 2> visited;
std::queue<const Inst*> queue;
queue.push(value.InstRecursive());
while (!queue.empty()) {
// Pop one instruction from the queue
const Inst* const inst{queue.front()};
queue.pop();
if (const std::optional result = pred(inst)) {
// This is the instruction we were looking for
return result;
}
// Visit the right most arguments first
for (size_t arg = inst->NumArgs(); arg--;) {
const Value arg_value{inst->Arg(arg)};
if (arg_value.IsImmediate()) {
continue;
}
// Queue instruction if it hasn't been visited
const Inst* const arg_inst{arg_value.InstRecursive()};
if (std::ranges::find(visited, arg_inst) == visited.end()) {
visited.push_back(arg_inst);
queue.push(arg_inst);
}
}
}
// SSA tree has been traversed and the result hasn't been found
return std::nullopt;
}
} // namespace Shader::IR

View file

@ -4,8 +4,8 @@
#include <algorithm>
#include <deque>
#include <boost/container/small_vector.hpp>
#include "shader_recompiler/ir/basic_block.h"
#include "shader_recompiler/ir/breadth_first_search.h"
#include "shader_recompiler/ir/ir_emitter.h"
#include "shader_recompiler/ir/program.h"
#include "shader_recompiler/runtime_info.h"
@ -244,22 +244,19 @@ SharpLocation TrackSharp(const IR::Inst* inst) {
const IR::Inst* spgpr_base = inst->Arg(0).InstRecursive();
// Retrieve SGPR pair that holds sbase
const IR::Inst* sbase0 = spgpr_base->Arg(0).InstRecursive();
const IR::Inst* sbase1 = spgpr_base->Arg(1).InstRecursive();
while (sbase0->GetOpcode() == IR::Opcode::Phi) {
sbase0 = sbase0->Arg(0).TryInstRecursive();
}
while (sbase1->GetOpcode() == IR::Opcode::Phi) {
sbase1 = sbase1->Arg(0).TryInstRecursive();
}
ASSERT_MSG(sbase0->GetOpcode() == IR::Opcode::GetUserData &&
sbase1->GetOpcode() == IR::Opcode::GetUserData,
"Nested resource loads not supported");
const IR::ScalarReg base = sbase0->Arg(0).ScalarReg();
const auto pred = [](const IR::Inst* inst) -> std::optional<IR::ScalarReg> {
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);
ASSERT_MSG(base0 && base1, "Nested resource loads not supported");
// Return retrieved location.
return SharpLocation{
.sgpr_base = u32(base),
.sgpr_base = u32(base0.value()),
.dword_offset = dword_offset,
};
}

View file

@ -422,6 +422,13 @@ vk::Format SurfaceFormat(AmdGpu::DataFormat data_format, AmdGpu::NumberFormat nu
num_format == AmdGpu::NumberFormat::Sint) {
return vk::Format::eR16G16Sint;
}
if (data_format == AmdGpu::DataFormat::Format8_8_8_8 &&
num_format == AmdGpu::NumberFormat::Uscaled) {
return vk::Format::eR8G8B8A8Uscaled;
}
if (data_format == AmdGpu::DataFormat::Format16 && num_format == AmdGpu::NumberFormat::Unorm) {
return vk::Format::eR16Unorm;
}
UNREACHABLE_MSG("Unknown data_format={} and num_format={}", u32(data_format), u32(num_format));
}