video_core: Fix crash caused by malformed geo shaders (#1585)

This commit is contained in:
PabloMK7 2026-01-08 21:00:05 +01:00 committed by GitHub
parent 3dd7103e62
commit 0f9457e0d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 52 additions and 8 deletions

View File

@ -342,7 +342,8 @@ void PicaCore::WriteInternalReg(u32 id, u32 value, u32 mask, bool& stop_requeste
} else {
vs_setup.program_code[offset] = value;
vs_setup.MarkProgramCodeDirty();
if (!regs.internal.pipeline.gs_unit_exclusive_configuration) {
if (!regs.internal.pipeline.gs_unit_exclusive_configuration &&
regs.internal.pipeline.use_gs == PipelineRegs::UseGS::No) {
gs_setup.program_code[offset] = value;
gs_setup.MarkProgramCodeDirty();
}
@ -365,7 +366,8 @@ void PicaCore::WriteInternalReg(u32 id, u32 value, u32 mask, bool& stop_requeste
} else {
vs_setup.swizzle_data[offset] = value;
vs_setup.MarkSwizzleDataDirty();
if (!regs.internal.pipeline.gs_unit_exclusive_configuration) {
if (!regs.internal.pipeline.gs_unit_exclusive_configuration &&
regs.internal.pipeline.use_gs == PipelineRegs::UseGS::No) {
gs_setup.swizzle_data[offset] = value;
gs_setup.MarkSwizzleDataDirty();
}

View File

@ -1,4 +1,4 @@
// Copyright 2014 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -118,7 +118,21 @@ static void RunInterpreter(const ShaderSetup& setup, ShaderUnit& state,
bool is_break = false;
const u32 old_program_counter = program_counter;
const Instruction instr = {program_code[program_counter]};
// Always treat the last instruction of the program code as an
// end instruction. This fixes some games such as Thunder Blade
// or After Burner II which have malformed geo shaders without an
// end instruction crashing the emulator due to the program counter
// growing uncontrollably.
// TODO(PabloMK7): Find how real HW reacts to this, most likely the
// program counter wraps around after reaching the last instruction,
// but more testing is needed.
Instruction instr{};
if (program_counter < MAX_PROGRAM_CODE_LENGTH - 1) {
instr.hex = program_code[program_counter];
} else {
instr.opcode.Assign(OpCode::Id::END);
}
const SwizzlePattern swizzle = {swizzle_data[instr.common.operand_desc_id]};
Record<DebugDataRecord::CUR_INSTR>(debug_data, iteration, program_counter);

View File

@ -1,4 +1,4 @@
// Copyright 2023 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -899,7 +899,21 @@ void JitShader::Compile_NextInstr() {
l(instruction_labels[program_counter]);
const Instruction instr = {(*program_code)[program_counter++]};
// Always treat the last instruction of the program code as an
// end instruction. This fixes some games such as Thunder Blade
// or After Burner II which have malformed geo shaders without an
// end instruction crashing the emulator due to the program counter
// growing uncontrollably.
// TODO(PabloMK7): Find how real HW reacts to this, most likely the
// program counter wraps around after reaching the last instruction,
// but more testing is needed.
Instruction instr{};
if (program_counter < MAX_PROGRAM_CODE_LENGTH - 1) {
instr.hex = (*program_code)[program_counter];
} else {
instr.opcode.Assign(OpCode::Id::END);
}
++program_counter;
const OpCode::Id opcode = instr.opcode.Value();
const auto instr_func = instr_table[static_cast<std::size_t>(opcode)];

View File

@ -1,4 +1,4 @@
// Copyright 2015 Citra Emulator Project
// Copyright Citra Emulator Project / Azahar Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@ -936,7 +936,21 @@ void JitShader::Compile_NextInstr() {
L(instruction_labels[program_counter]);
Instruction instr = {(*program_code)[program_counter++]};
// Always treat the last instruction of the program code as an
// end instruction. This fixes some games such as Thunder Blade
// or After Burner II which have malformed geo shaders without an
// end instruction crashing the emulator due to the program counter
// growing uncontrollably.
// TODO(PabloMK7): Find how real HW reacts to this, most likely the
// program counter wraps around after reaching the last instruction,
// but more testing is needed.
Instruction instr{};
if (program_counter < MAX_PROGRAM_CODE_LENGTH - 1) {
instr.hex = (*program_code)[program_counter];
} else {
instr.opcode.Assign(OpCode::Id::END);
}
++program_counter;
OpCode::Id opcode = instr.opcode.Value();
auto instr_func = instr_table[static_cast<u32>(opcode)];