mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-07 23:41:26 +12:00
vp: Improve vertex program analyser
- Adds dead code elimination - Fix absolute branch target addresses to take base address into account - Patch branch targets relative to base address to improve hash matching - Bumps shader cache version - Enables shader logging option to write out vertex program binary, helpful when debugging problems.
This commit is contained in:
parent
bd915bfebd
commit
2ca935a26b
12 changed files with 427 additions and 172 deletions
|
@ -409,106 +409,54 @@ std::string VertexProgramDecompiler::BuildCode()
|
|||
}
|
||||
|
||||
VertexProgramDecompiler::VertexProgramDecompiler(const RSXVertexProgram& prog) :
|
||||
m_data(prog.data)
|
||||
m_prog(prog)
|
||||
{
|
||||
}
|
||||
|
||||
std::string VertexProgramDecompiler::Decompile()
|
||||
{
|
||||
for (unsigned i = 0; i < PF_PARAM_COUNT; i++)
|
||||
m_parr.params[i].clear();
|
||||
|
||||
m_instr_count = m_data.size() / 4;
|
||||
|
||||
for (int i = 0; i < m_max_instr_count; ++i)
|
||||
{
|
||||
m_instructions[i].reset();
|
||||
}
|
||||
const auto& data = m_prog.data;
|
||||
m_instr_count = data.size() / 4;
|
||||
|
||||
bool is_has_BRA = false;
|
||||
bool program_end = false;
|
||||
u32 i = 1;
|
||||
u32 last_label_addr = 0;
|
||||
|
||||
while (i < m_data.size())
|
||||
for (unsigned i = 0; i < PF_PARAM_COUNT; i++)
|
||||
{
|
||||
if (is_has_BRA)
|
||||
{
|
||||
d3.HEX = m_data[i];
|
||||
i += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
d1.HEX = m_data[i++];
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_parr.params[i].clear();
|
||||
}
|
||||
|
||||
uint jump_position = 0;
|
||||
if (is_has_BRA || !m_jump_lvls.empty())
|
||||
for (int i = 0; i < m_max_instr_count; ++i)
|
||||
{
|
||||
m_cur_instr = &m_instructions[0];
|
||||
AddCode("int jump_position = 0;");
|
||||
AddCode("while (true)");
|
||||
AddCode("{");
|
||||
m_cur_instr->open_scopes++;
|
||||
m_instructions[i].reset();
|
||||
}
|
||||
|
||||
AddCode(fmt::format("if (jump_position <= %u)", jump_position++));
|
||||
AddCode("{");
|
||||
m_cur_instr->open_scopes++;
|
||||
if (m_prog.jump_table.size())
|
||||
{
|
||||
last_label_addr = *m_prog.jump_table.rbegin();
|
||||
}
|
||||
|
||||
auto find_jump_lvl = [this](u32 address)
|
||||
{
|
||||
u32 jump = 1;
|
||||
|
||||
for (auto pos : m_jump_lvls)
|
||||
for (auto pos : m_prog.jump_table)
|
||||
{
|
||||
if (address == pos)
|
||||
break;
|
||||
return jump;
|
||||
|
||||
++jump;
|
||||
}
|
||||
|
||||
return jump;
|
||||
return UINT32_MAX;
|
||||
};
|
||||
|
||||
auto do_function_call = [this, &i](const std::string& condition)
|
||||
{
|
||||
//call function
|
||||
// Call function
|
||||
// NOTE: Addresses are assumed to have been patched
|
||||
m_call_stack.push(i+1);
|
||||
AddCode(condition);
|
||||
AddCode("{");
|
||||
|
@ -552,17 +500,41 @@ std::string VertexProgramDecompiler::Decompile()
|
|||
}
|
||||
};
|
||||
|
||||
for (i = 0; i < m_instr_count; ++i)
|
||||
if (is_has_BRA || !m_prog.jump_table.empty())
|
||||
{
|
||||
if (m_call_stack.empty())
|
||||
m_cur_instr = &m_instructions[0];
|
||||
|
||||
u32 jump_position = 0;
|
||||
if (m_prog.entry != m_prog.base_address)
|
||||
{
|
||||
m_cur_instr = &m_instructions[i];
|
||||
jump_position = find_jump_lvl(m_prog.entry - m_prog.base_address);
|
||||
verify(HERE), jump_position != UINT32_MAX;
|
||||
}
|
||||
|
||||
d0.HEX = m_data[i * 4 + 0];
|
||||
d1.HEX = m_data[i * 4 + 1];
|
||||
d2.HEX = m_data[i * 4 + 2];
|
||||
d3.HEX = m_data[i * 4 + 3];
|
||||
AddCode(fmt::format("int jump_position = %u;", jump_position));
|
||||
AddCode("while (true)");
|
||||
AddCode("{");
|
||||
m_cur_instr->open_scopes++;
|
||||
|
||||
AddCode("if (jump_position <= 0)");
|
||||
AddCode("{");
|
||||
m_cur_instr->open_scopes++;
|
||||
}
|
||||
|
||||
for (i = 0; i < m_instr_count; ++i)
|
||||
{
|
||||
if (!m_prog.instruction_mask[i])
|
||||
{
|
||||
// Dead code, skip
|
||||
continue;
|
||||
}
|
||||
|
||||
m_cur_instr = &m_instructions[i];
|
||||
|
||||
d0.HEX = data[i * 4 + 0];
|
||||
d1.HEX = data[i * 4 + 1];
|
||||
d2.HEX = data[i * 4 + 2];
|
||||
d3.HEX = data[i * 4 + 3];
|
||||
|
||||
src[0].src0l = d2.src0l;
|
||||
src[0].src0h = d1.src0h;
|
||||
|
@ -570,27 +542,29 @@ std::string VertexProgramDecompiler::Decompile()
|
|||
src[2].src2l = d3.src2l;
|
||||
src[2].src2h = d2.src2h;
|
||||
|
||||
if (!src[0].reg_type || !src[1].reg_type || !src[2].reg_type)
|
||||
{
|
||||
AddCode("//Src check failed. Aborting");
|
||||
program_end = true;
|
||||
}
|
||||
|
||||
if (m_call_stack.empty())
|
||||
if (m_call_stack.empty() && i)
|
||||
{
|
||||
//TODO: Subroutines can also have arbitrary jumps!
|
||||
if (i && (is_has_BRA || std::find(m_jump_lvls.begin(), m_jump_lvls.end(), i) != m_jump_lvls.end()))
|
||||
u32 jump_position = find_jump_lvl(i);
|
||||
if (is_has_BRA || jump_position != UINT32_MAX)
|
||||
{
|
||||
m_cur_instr->close_scopes++;
|
||||
AddCode("}");
|
||||
AddCode("");
|
||||
|
||||
AddCode(fmt::format("if (jump_position <= %u)", jump_position++));
|
||||
AddCode(fmt::format("if (jump_position <= %u)", jump_position));
|
||||
AddCode("{");
|
||||
m_cur_instr->open_scopes++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!src[0].reg_type || !src[1].reg_type || !src[2].reg_type)
|
||||
{
|
||||
AddCode("//Src check failed. Aborting");
|
||||
program_end = true;
|
||||
d1.vec_opcode = d1.sca_opcode = 0;
|
||||
}
|
||||
|
||||
switch (d1.vec_opcode)
|
||||
{
|
||||
case RSX_VEC_OPCODE_NOP: break;
|
||||
|
@ -754,7 +728,7 @@ std::string VertexProgramDecompiler::Decompile()
|
|||
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");
|
||||
LOG_ERROR(RSX, "Vertex program block aborts prematurely. Expect glitches");
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -762,7 +736,7 @@ std::string VertexProgramDecompiler::Decompile()
|
|||
}
|
||||
}
|
||||
|
||||
if (is_has_BRA || !m_jump_lvls.empty())
|
||||
if (is_has_BRA || !m_prog.jump_table.empty())
|
||||
{
|
||||
m_cur_instr = &m_instructions[m_instr_count - 1];
|
||||
m_cur_instr->close_scopes++;
|
||||
|
@ -774,8 +748,6 @@ std::string VertexProgramDecompiler::Decompile()
|
|||
|
||||
std::string result = BuildCode();
|
||||
|
||||
m_jump_lvls.clear();
|
||||
m_body.clear();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue