mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2024-12-28 18:46:06 +00:00
video_core/amdgpu: heuristic for shader binary info
Games can strip the first shader instruction (meant for debugging) which we rely on for obtaining shader information (e.g. LittleBigPlanet 3). For this reason, we start a search through the code start until we arrive at the shader binary info.
This commit is contained in:
parent
2a0629477b
commit
e968b1c23f
|
@ -32,7 +32,9 @@ IR::Program TranslateProgram(std::span<const u32> code, Pools& pools, Info& info
|
||||||
const RuntimeInfo& runtime_info, const Profile& profile) {
|
const RuntimeInfo& runtime_info, const Profile& profile) {
|
||||||
// Ensure first instruction is expected.
|
// Ensure first instruction is expected.
|
||||||
constexpr u32 token_mov_vcchi = 0xBEEB03FF;
|
constexpr u32 token_mov_vcchi = 0xBEEB03FF;
|
||||||
ASSERT_MSG(code[0] == token_mov_vcchi, "First instruction is not s_mov_b32 vcc_hi, #imm");
|
if (code[0] != token_mov_vcchi) {
|
||||||
|
LOG_WARNING(Render_Recompiler, "First instruction is not s_mov_b32 vcc_hi, #imm");
|
||||||
|
}
|
||||||
|
|
||||||
Gcn::GcnCodeSlice slice(code.data(), code.data() + code.size());
|
Gcn::GcnCodeSlice slice(code.data(), code.data() + code.size());
|
||||||
Gcn::GcnDecodeContext decoder;
|
Gcn::GcnDecodeContext decoder;
|
||||||
|
|
|
@ -88,6 +88,32 @@ struct Liverpool {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const BinaryInfo& SearchBinaryInfo(const u32* code, size_t search_limit = 0x1000) {
|
||||||
|
constexpr u32 token_mov_vcchi = 0xBEEB03FF;
|
||||||
|
|
||||||
|
if (code[0] == token_mov_vcchi) {
|
||||||
|
const auto* info = std::bit_cast<const BinaryInfo*>(code + (code[1] + 1) * 2);
|
||||||
|
if (info->Valid()) {
|
||||||
|
return *info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// First instruction is not s_mov_b32 vcc_hi, #imm,
|
||||||
|
// which means we cannot get the binary info via said instruction.
|
||||||
|
// The easiest solution is to iterate through each dword and break
|
||||||
|
// on the first instance of the binary info.
|
||||||
|
constexpr size_t signature_size = sizeof(BinaryInfo::signature_ref) / sizeof(u8);
|
||||||
|
const u32* end = code + search_limit;
|
||||||
|
|
||||||
|
for (const u32* it = code; it < end; ++it) {
|
||||||
|
if (const BinaryInfo* info = std::bit_cast<const BinaryInfo*>(it); info->Valid()) {
|
||||||
|
return *info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UNREACHABLE_MSG("Shader binary info not found.");
|
||||||
|
}
|
||||||
|
|
||||||
struct ShaderProgram {
|
struct ShaderProgram {
|
||||||
u32 address_lo;
|
u32 address_lo;
|
||||||
BitField<0, 8, u32> address_hi;
|
BitField<0, 8, u32> address_hi;
|
||||||
|
@ -113,8 +139,7 @@ struct Liverpool {
|
||||||
|
|
||||||
std::span<const u32> Code() const {
|
std::span<const u32> Code() const {
|
||||||
const u32* code = Address<u32*>();
|
const u32* code = Address<u32*>();
|
||||||
BinaryInfo bininfo;
|
const BinaryInfo& bininfo = SearchBinaryInfo(code);
|
||||||
std::memcpy(&bininfo, code + (code[1] + 1) * 2, sizeof(bininfo));
|
|
||||||
const u32 num_dwords = bininfo.length / sizeof(u32);
|
const u32 num_dwords = bininfo.length / sizeof(u32);
|
||||||
return std::span{code, num_dwords};
|
return std::span{code, num_dwords};
|
||||||
}
|
}
|
||||||
|
@ -166,27 +191,24 @@ struct Liverpool {
|
||||||
|
|
||||||
std::span<const u32> Code() const {
|
std::span<const u32> Code() const {
|
||||||
const u32* code = Address<u32*>();
|
const u32* code = Address<u32*>();
|
||||||
BinaryInfo bininfo;
|
const BinaryInfo& bininfo = SearchBinaryInfo(code);
|
||||||
std::memcpy(&bininfo, code + (code[1] + 1) * 2, sizeof(bininfo));
|
|
||||||
const u32 num_dwords = bininfo.length / sizeof(u32);
|
const u32 num_dwords = bininfo.length / sizeof(u32);
|
||||||
return std::span{code, num_dwords};
|
return std::span{code, num_dwords};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Shader>
|
template <typename Shader>
|
||||||
static constexpr auto* GetBinaryInfo(const Shader& sh) {
|
static constexpr const BinaryInfo& GetBinaryInfo(const Shader& sh) {
|
||||||
const auto* code = sh.template Address<u32*>();
|
const auto* code = sh.template Address<u32*>();
|
||||||
const auto* bininfo = std::bit_cast<const BinaryInfo*>(code + (code[1] + 1) * 2);
|
return SearchBinaryInfo(code);
|
||||||
// ASSERT_MSG(bininfo->Valid(), "Invalid shader binary header");
|
|
||||||
return bininfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr Shader::ShaderParams GetParams(const auto& sh) {
|
static constexpr Shader::ShaderParams GetParams(const auto& sh) {
|
||||||
auto* bininfo = GetBinaryInfo(sh);
|
auto& bininfo = GetBinaryInfo(sh);
|
||||||
return {
|
return {
|
||||||
.user_data = sh.user_data,
|
.user_data = sh.user_data,
|
||||||
.code = sh.Code(),
|
.code = sh.Code(),
|
||||||
.hash = bininfo->shader_hash,
|
.hash = bininfo.shader_hash,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -292,8 +292,8 @@ bool PipelineCache::RefreshGraphicsKey() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto* bininfo = Liverpool::GetBinaryInfo(*pgm);
|
const auto& bininfo = Liverpool::GetBinaryInfo(*pgm);
|
||||||
if (!bininfo->Valid()) {
|
if (!bininfo.Valid()) {
|
||||||
LOG_WARNING(Render_Vulkan, "Invalid binary info structure!");
|
LOG_WARNING(Render_Vulkan, "Invalid binary info structure!");
|
||||||
key.stage_hashes[stage_out_idx] = 0;
|
key.stage_hashes[stage_out_idx] = 0;
|
||||||
infos[stage_out_idx] = nullptr;
|
infos[stage_out_idx] = nullptr;
|
||||||
|
|
Loading…
Reference in a new issue