mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2024-07-04 23:31:19 +01:00
shader_ir/memory: Ignore global memory when tracking fails
Ignore global memory operations instead of invoking undefined behaviour when constant buffer tracking fails and we are blasting through asserts, ignore the operation. In the case of LDG this means filling the destination registers with zeroes; for STG this means ignore the instruction as a whole. The default behaviour is still to abort execution on failure.
This commit is contained in:
parent
dd2e96b362
commit
1ea07954fb
2 changed files with 26 additions and 18 deletions
|
@ -166,9 +166,17 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
|
||||||
}();
|
}();
|
||||||
|
|
||||||
const auto [real_address_base, base_address, descriptor] =
|
const auto [real_address_base, base_address, descriptor] =
|
||||||
TrackAndGetGlobalMemory(bb, instr, false);
|
TrackGlobalMemory(bb, instr, false);
|
||||||
|
|
||||||
const u32 count = GetUniformTypeElementsCount(type);
|
const u32 count = GetUniformTypeElementsCount(type);
|
||||||
|
if (!real_address_base || !base_address) {
|
||||||
|
// Tracking failed, load zeroes.
|
||||||
|
for (u32 i = 0; i < count; ++i) {
|
||||||
|
SetRegister(bb, instr.gpr0.Value() + i, Immediate(0.0f));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
for (u32 i = 0; i < count; ++i) {
|
for (u32 i = 0; i < count; ++i) {
|
||||||
const Node it_offset = Immediate(i * 4);
|
const Node it_offset = Immediate(i * 4);
|
||||||
const Node real_address =
|
const Node real_address =
|
||||||
|
@ -260,22 +268,19 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
|
||||||
}();
|
}();
|
||||||
|
|
||||||
const auto [real_address_base, base_address, descriptor] =
|
const auto [real_address_base, base_address, descriptor] =
|
||||||
TrackAndGetGlobalMemory(bb, instr, true);
|
TrackGlobalMemory(bb, instr, true);
|
||||||
|
if (!real_address_base || !base_address) {
|
||||||
// Encode in temporary registers like this: real_base_address, {registers_to_be_written...}
|
// Tracking failed, skip the store.
|
||||||
SetTemporary(bb, 0, real_address_base);
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const u32 count = GetUniformTypeElementsCount(type);
|
const u32 count = GetUniformTypeElementsCount(type);
|
||||||
for (u32 i = 0; i < count; ++i) {
|
|
||||||
SetTemporary(bb, i + 1, GetRegister(instr.gpr0.Value() + i));
|
|
||||||
}
|
|
||||||
for (u32 i = 0; i < count; ++i) {
|
for (u32 i = 0; i < count; ++i) {
|
||||||
const Node it_offset = Immediate(i * 4);
|
const Node it_offset = Immediate(i * 4);
|
||||||
const Node real_address =
|
const Node real_address = Operation(OperationCode::UAdd, real_address_base, it_offset);
|
||||||
Operation(OperationCode::UAdd, NO_PRECISE, real_address_base, it_offset);
|
|
||||||
const Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor);
|
const Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor);
|
||||||
|
const Node value = GetRegister(instr.gpr0.Value() + i);
|
||||||
bb.push_back(Operation(OperationCode::Assign, gmem, GetTemporary(i + 1)));
|
bb.push_back(Operation(OperationCode::Assign, gmem, value));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -301,15 +306,17 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
|
||||||
return pc;
|
return pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<Node, Node, GlobalMemoryBase> ShaderIR::TrackAndGetGlobalMemory(NodeBlock& bb,
|
std::tuple<Node, Node, GlobalMemoryBase> ShaderIR::TrackGlobalMemory(NodeBlock& bb,
|
||||||
Instruction instr,
|
Instruction instr,
|
||||||
bool is_write) {
|
bool is_write) {
|
||||||
const auto addr_register{GetRegister(instr.gmem.gpr)};
|
const auto addr_register{GetRegister(instr.gmem.gpr)};
|
||||||
const auto immediate_offset{static_cast<u32>(instr.gmem.offset)};
|
const auto immediate_offset{static_cast<u32>(instr.gmem.offset)};
|
||||||
|
|
||||||
const auto [base_address, index, offset] =
|
const auto [base_address, index, offset] =
|
||||||
TrackCbuf(addr_register, global_code, static_cast<s64>(global_code.size()));
|
TrackCbuf(addr_register, global_code, static_cast<s64>(global_code.size()));
|
||||||
ASSERT(base_address != nullptr);
|
ASSERT_OR_EXECUTE_MSG(base_address != nullptr,
|
||||||
|
{ return std::make_tuple(nullptr, nullptr, GlobalMemoryBase{}); },
|
||||||
|
"Global memory tracking failed");
|
||||||
|
|
||||||
bb.push_back(Comment(fmt::format("Base address is c[0x{:x}][0x{:x}]", index, offset)));
|
bb.push_back(Comment(fmt::format("Base address is c[0x{:x}][0x{:x}]", index, offset)));
|
||||||
|
|
||||||
|
|
|
@ -371,8 +371,9 @@ private:
|
||||||
std::pair<Node, s64> TrackRegister(const GprNode* tracked, const NodeBlock& code,
|
std::pair<Node, s64> TrackRegister(const GprNode* tracked, const NodeBlock& code,
|
||||||
s64 cursor) const;
|
s64 cursor) const;
|
||||||
|
|
||||||
std::tuple<Node, Node, GlobalMemoryBase> TrackAndGetGlobalMemory(
|
std::tuple<Node, Node, GlobalMemoryBase> TrackGlobalMemory(NodeBlock& bb,
|
||||||
NodeBlock& bb, Tegra::Shader::Instruction instr, bool is_write);
|
Tegra::Shader::Instruction instr,
|
||||||
|
bool is_write);
|
||||||
|
|
||||||
const ProgramCode& program_code;
|
const ProgramCode& program_code;
|
||||||
const u32 main_offset;
|
const u32 main_offset;
|
||||||
|
|
Loading…
Reference in a new issue