nx2: title 4's intro cutscene renders correctly
Native shader capture counted CALL.REL.NOINC as a function call, so a program using it waited for a RET after its EXIT and read on into the following shaders until a garbage branch target made it fail. NOINC calls push no return address (the compiler uses them as jumps; the lowering already treats them so): count them as forward branches. That shader builds title 4's 3D colour-grading LUT once per scene; with it rejected the LUT stayed empty and the tonemap turned every frame black. The intro cutscene now renders lit and graded, with subtitles, through the bilinear stand-in for the tensor-core upscaler. Also: rejected captures dump to EDEN_NX2_SHADER_DUMP as rejected-<addr>.bin and report the offending instruction.
This commit is contained in:
parent
465eeb8598
commit
fe5cb5efdf
2 changed files with 17 additions and 3 deletions
|
|
@ -19,7 +19,10 @@ public:
|
|||
const s64 target = s64{index} * 16 + 16 + relative;
|
||||
if (target < 0 || target % 16 || target >= MaximumInstructions * 16)
|
||||
return Result::InvalidTarget;
|
||||
if (opcode == 0x944) {
|
||||
// CALL.REL.NOINC (bit 86) pushes no return address: the compiler uses it as a jump
|
||||
// (the lowering treats it as one), so it never pairs with a RET.
|
||||
const bool noinc_call = opcode == 0x944 && (instruction.words[2] & 0x400000) != 0;
|
||||
if (opcode == 0x944 && !noinc_call) {
|
||||
last_call_target = std::max(last_call_target, static_cast<u32>(target / 16));
|
||||
} else {
|
||||
last_forward_target = std::max(last_forward_target, static_cast<u32>(target / 16));
|
||||
|
|
|
|||
|
|
@ -338,8 +338,19 @@ void GenericEnvironment::InitializeNativeCode(u32 source_header_size) {
|
|||
auto& instruction = native.emplace_back();
|
||||
gpu_memory->ReadBlock(address, &instruction, sizeof(instruction));
|
||||
const auto status = capture.Observe(instruction, index);
|
||||
if (status == Shader::Ampere::ProgramCaptureState::Result::InvalidTarget)
|
||||
throw Shader::RuntimeError("Native shader branch outside capture bounds");
|
||||
if (status == Shader::Ampere::ProgramCaptureState::Result::InvalidTarget) {
|
||||
if (const char* dir = std::getenv("EDEN_NX2_SHADER_DUMP")) {
|
||||
const auto path = fmt::format("{}/rejected-{:x}.bin", dir, program_base + native_header_size);
|
||||
if (std::FILE* file = std::fopen(path.c_str(), "wb")) {
|
||||
std::fwrite(native.data(), sizeof(Instruction), std::min<size_t>(native.size(), 4096), file);
|
||||
std::fclose(file);
|
||||
}
|
||||
}
|
||||
throw Shader::RuntimeError("Native shader branch outside capture bounds at {:#x} +{:#x} [{:08x} {:08x} {:08x} {:08x}]",
|
||||
program_base + native_header_size, index * 16,
|
||||
instruction.words[0], instruction.words[1],
|
||||
instruction.words[2], instruction.words[3]);
|
||||
}
|
||||
if (status == Shader::Ampere::ProgramCaptureState::Result::Complete) break;
|
||||
}
|
||||
auto lowered = Shader::Ampere::LowerToMaxwell(native);
|
||||
|
|
|
|||
Loading…
Reference in a new issue