diff --git a/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp b/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp index 1e4ec8806e..b4dcf35e04 100644 --- a/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Common/VertexProgramDecompiler.cpp @@ -428,6 +428,7 @@ std::string VertexProgramDecompiler::Decompile() bool is_has_BRA = false; bool program_end = false; u32 i = 1; + u32 last_label_addr = 0; while (i < m_data.size()) { @@ -443,29 +444,36 @@ std::string VertexProgramDecompiler::Decompile() switch (d1.sca_opcode) { case RSX_SCA_OPCODE_BRA: + { LOG_ERROR(RSX, "Unimplemented VP opcode BRA"); is_has_BRA = true; m_jump_lvls.clear(); d3.HEX = m_data[++i]; i += 4; break; - + } case RSX_SCA_OPCODE_BRB: case RSX_SCA_OPCODE_BRI: case RSX_SCA_OPCODE_CAL: case RSX_SCA_OPCODE_CLI: case RSX_SCA_OPCODE_CLB: + { d2.HEX = m_data[i++]; d3.HEX = m_data[i]; i += 2; - m_jump_lvls.emplace(GetAddr()); - break; + const u32 label_addr = GetAddr(); + last_label_addr = std::max(last_label_addr, label_addr); + m_jump_lvls.emplace(label_addr); + break; + } default: + { d3.HEX = m_data[++i]; i += 2; break; } + } } } @@ -565,8 +573,7 @@ std::string VertexProgramDecompiler::Decompile() if (!src[0].reg_type || !src[1].reg_type || !src[2].reg_type) { AddCode("//Src check failed. Aborting"); - do_program_exit(true); - break; + program_end = true; } if (m_call_stack.empty()) @@ -584,8 +591,6 @@ std::string VertexProgramDecompiler::Decompile() } } - program_end = !!d3.end; - switch (d1.vec_opcode) { case RSX_VEC_OPCODE_NOP: break; @@ -640,7 +645,7 @@ std::string VertexProgramDecompiler::Decompile() { if (m_call_stack.empty()) { - AddCode("$if ($cond) //BRA"); + AddCode("$ifcond //BRA"); AddCode("{"); m_cur_instr->open_scopes++; AddCode("jump_position = $a$am;"); @@ -698,8 +703,6 @@ std::string VertexProgramDecompiler::Decompile() case RSX_SCA_OPCODE_BRB: // works differently (BRB o[1].x !b0, L0;) { - LOG_WARNING(RSX, "sca_opcode BRB, d0=0x%X, d1=0x%X, d2=0x%X, d3=0x%X", d0.HEX, d1.HEX, d2.HEX, d3.HEX); - if (m_call_stack.empty()) { u32 jump_position = find_jump_lvl(GetAddr()); @@ -742,10 +745,20 @@ std::string VertexProgramDecompiler::Decompile() break; } - if (program_end) + if (program_end || !!d3.end) { do_program_exit(!d3.end); - break; + + if (i >= last_label_addr) + { + if ((i + 1) < m_instr_count) + { + // In rare cases, this might be harmless (large coalesced program blocks controlled via branches aka ubershaders) + LOG_ERROR(RSX, "Vertex program aborted prematurely. Expect glitches"); + } + + break; + } } } diff --git a/rpcs3/Emu/RSX/rsx_methods.cpp b/rpcs3/Emu/RSX/rsx_methods.cpp index 5096f3b60f..fed6265522 100644 --- a/rpcs3/Emu/RSX/rsx_methods.cpp +++ b/rpcs3/Emu/RSX/rsx_methods.cpp @@ -340,9 +340,11 @@ namespace rsx static constexpr u32 reg = index / 4; static constexpr u8 subreg = index % 4; - u32 load = rsx::method_registers.transform_constant_load(); - if ((load + index) >= 512) + const u32 load = rsx::method_registers.transform_constant_load(); + const u32 address = load + reg; + if (address >= 468) { + // Ignore addresses outside the usable [0, 467] range LOG_ERROR(RSX, "Invalid transform register index (load=%d, index=%d)", load, index); return; } @@ -538,7 +540,7 @@ namespace rsx rsx->sync(); } - void invalidate_L2(thread* rsx, u32, u32) + void set_shader_program_dirty(thread* rsx, u32, u32) { rsx->m_graphics_state |= rsx::pipeline_state::fragment_program_dirty; } @@ -1757,7 +1759,7 @@ namespace rsx bind_range(); bind_range(); bind_range(); - bind_range(); + bind_range(); bind_range(); bind_range(); bind_range(); @@ -1782,7 +1784,8 @@ namespace rsx bind(); bind(); bind(); - bind(); + bind(); + bind(); bind(); bind();