Skip to content

Commit 01ec267

Browse files
committed
rsx-debugger: Show disassembly of the currently active VP and FP
1 parent dd0004f commit 01ec267

File tree

3 files changed

+142
-20
lines changed

3 files changed

+142
-20
lines changed

rpcs3/Emu/RSX/rsx_methods.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,11 @@ namespace rsx
705705
return decode<NV4097_SET_USER_CLIP_PLANE_CONTROL>().clip_plane5();
706706
}
707707

708+
u32 clip_planes_mask() const
709+
{
710+
return registers[NV4097_SET_USER_CLIP_PLANE_CONTROL];
711+
}
712+
708713
front_face front_face_mode() const
709714
{
710715
return decode<NV4097_SET_FRONT_FACE>().front_face_mode();

rpcs3/rpcs3qt/rsx_debugger.cpp

Lines changed: 131 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include "table_item_delegate.h"
55
#include "Emu/RSX/RSXThread.h"
66
#include "Emu/RSX/gcm_printing.h"
7+
#include "Emu/RSX/Common/BufferUtils.h"
8+
#include "Emu/RSX/Program/CgBinaryProgram.h"
79
#include "Utilities/File.h"
810

911
#include <QHBoxLayout>
@@ -123,17 +125,6 @@ rsx_debugger::rsx_debugger(std::shared_ptr<gui_settings> gui_settings, QWidget*
123125
vbox_tools->addLayout(hbox_controls);
124126
vbox_tools->addWidget(m_tw_rsx);
125127

126-
// State explorer
127-
m_text_transform_program = new QLabel();
128-
m_text_transform_program->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
129-
m_text_transform_program->setFont(mono);
130-
m_text_transform_program->setText("");
131-
132-
m_text_shader_program = new QLabel();
133-
m_text_shader_program->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
134-
m_text_shader_program->setFont(mono);
135-
m_text_shader_program->setText("");
136-
137128
m_list_index_buffer = new QListWidget();
138129
m_list_index_buffer->setFont(mono);
139130

@@ -208,11 +199,31 @@ rsx_debugger::rsx_debugger(std::shared_ptr<gui_settings> gui_settings, QWidget*
208199
QWidget* buffers = new QWidget();
209200
buffers->setLayout(buffer_layout);
210201

202+
auto xp_layout = new QHBoxLayout();
203+
m_transform_disasm = new QTextEdit(this);
204+
m_transform_disasm->setReadOnly(true);
205+
m_transform_disasm->setWordWrapMode(QTextOption::NoWrap);
206+
m_transform_disasm->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
207+
xp_layout->addWidget(m_transform_disasm);
208+
209+
auto xp_tab = new QWidget();
210+
xp_tab->setLayout(xp_layout);
211+
212+
auto fp_layout = new QHBoxLayout();
213+
m_fragment_disasm = new QTextEdit(this);
214+
m_fragment_disasm->setReadOnly(true);
215+
m_fragment_disasm->setWordWrapMode(QTextOption::NoWrap);
216+
m_fragment_disasm->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
217+
fp_layout->addWidget(m_fragment_disasm);
218+
219+
auto fp_tab = new QWidget();
220+
fp_tab->setLayout(fp_layout);
221+
211222
QTabWidget* state_rsx = new QTabWidget();
212223
state_rsx->addTab(buffers, tr("RTTs and DS"));
213-
state_rsx->addTab(m_text_transform_program, tr("Transform program"));
214-
state_rsx->addTab(m_text_shader_program, tr("Shader program"));
215-
state_rsx->addTab(m_list_index_buffer, tr("Index buffer"));
224+
state_rsx->addTab(xp_tab, tr("Vertex Program"));
225+
state_rsx->addTab(fp_tab, tr("Fragment Program"));
226+
state_rsx->addTab(m_list_index_buffer, tr("Index Buffer"));
216227

217228
QHBoxLayout* main_layout = new QHBoxLayout();
218229
main_layout->addLayout(vbox_tools, 1);
@@ -592,10 +603,10 @@ void rsx_debugger::OnClickDrawCalls()
592603
}
593604

594605
// Programs
595-
m_text_transform_program->clear();
596-
m_text_transform_program->setText(qstr(frame_debug.draw_calls[draw_id].programs.first));
597-
m_text_shader_program->clear();
598-
m_text_shader_program->setText(qstr(frame_debug.draw_calls[draw_id].programs.second));
606+
m_transform_disasm->clear();
607+
m_transform_disasm->setText(qstr(frame_debug.draw_calls[draw_id].programs.first));
608+
m_fragment_disasm->clear();
609+
m_fragment_disasm->setText(qstr(frame_debug.draw_calls[draw_id].programs.second));
599610

600611
m_list_index_buffer->clear();
601612
//m_list_index_buffer->insertColumn(0, "Index", 0, 700);
@@ -621,6 +632,8 @@ void rsx_debugger::UpdateInformation() const
621632
{
622633
GetMemory();
623634
GetBuffers();
635+
GetVertexProgram();
636+
GetFragmentProgram();
624637
}
625638

626639
void rsx_debugger::GetMemory() const
@@ -1202,3 +1215,103 @@ void rsx_debugger::GetBuffers() const
12021215

12031216
m_buffer_tex->showImage(QImage(m_buffer_tex->cache.data(), width, height, QImage::Format_RGB32));
12041217
}
1218+
1219+
void rsx_debugger::GetVertexProgram() const
1220+
{
1221+
const auto render = rsx::get_current_renderer();
1222+
if (!render || !render->is_initialized || !render->local_mem_size || !render->is_paused())
1223+
{
1224+
return;
1225+
}
1226+
1227+
RSXVertexProgram vp;
1228+
vp.data.reserve(512 * 4);
1229+
1230+
const u32 vp_entry = rsx::method_registers.transform_program_start();
1231+
const auto vp_metadata = program_hash_util::vertex_program_utils::analyse_vertex_program
1232+
(
1233+
rsx::method_registers.transform_program.data(), // Input raw block
1234+
vp_entry, // Address of entry point
1235+
vp // [out] Program object
1236+
);
1237+
1238+
const u32 ucode_len = static_cast<u32>(vp.data.size() * sizeof(u32));
1239+
std::vector<u32> vp_blob = {
1240+
7003u, // Type
1241+
6u, // Revision
1242+
56u + ucode_len, // Total size
1243+
0, // paramCount
1244+
0, // paramArray
1245+
32u, // Program header offset
1246+
ucode_len, // Ucode length
1247+
56u, // Ucode start
1248+
1249+
::size32(vp.data) / 4, // Instruction count
1250+
0, // Slot
1251+
16u, // Registers used
1252+
rsx::method_registers.vertex_attrib_input_mask(),
1253+
rsx::method_registers.vertex_attrib_output_mask(),
1254+
rsx::method_registers.clip_planes_mask()
1255+
};
1256+
1257+
vp_blob.resize(vp_blob.size() + vp.data.size());
1258+
std::copy(vp.data.begin(), vp.data.end(), vp_blob.begin() + 14);
1259+
1260+
std::span<u32> vp_binary(vp_blob);
1261+
CgBinaryDisasm vp_disasm(vp_binary);
1262+
vp_disasm.BuildShaderBody(false);
1263+
1264+
m_transform_disasm->clear();
1265+
m_transform_disasm->setText(QString::fromStdString(vp_disasm.GetArbShader()));
1266+
}
1267+
1268+
void rsx_debugger::GetFragmentProgram() const
1269+
{
1270+
const auto render = rsx::get_current_renderer();
1271+
if (!render || !render->is_initialized || !render->local_mem_size || !render->is_paused())
1272+
{
1273+
return;
1274+
}
1275+
1276+
const auto [program_offset, program_location] = rsx::method_registers.shader_program_address();
1277+
auto data_ptr = vm::base(rsx::get_address(program_offset, program_location));
1278+
const auto fp_metadata = program_hash_util::fragment_program_utils::analyse_fragment_program(data_ptr);
1279+
1280+
const bool output_h0 = rsx::method_registers.shader_control() & CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS ? false : true;
1281+
const bool depth_replace = rsx::method_registers.shader_control() & CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT ? true : false;
1282+
const u32 flags = 16u /* Reg count */ | ((output_h0 /* 16-bit exports? */ ? 1u : 0u) << 8u) | ((depth_replace /* Export depth? */ ? 1u : 0u) << 16u) | (0u /* Uses KILL? */ << 24u);
1283+
const auto ucode_len = fp_metadata.program_ucode_length;
1284+
1285+
std::vector<u32> blob = {
1286+
7004u, // Type
1287+
6u, // Revision
1288+
56u + ucode_len, // Total size
1289+
0, // paramCount
1290+
0, // paramArray
1291+
32u, // Program header offset
1292+
ucode_len, // Ucode length
1293+
56u, // Ucode start
1294+
1295+
ucode_len / 16, // Instruction count
1296+
rsx::method_registers.vertex_attrib_output_mask(), // Slot
1297+
0u, // Partial load
1298+
0u | (rsx::method_registers.texcoord_control_mask() << 16u), // Texcoord input mask | tex2d control
1299+
0u | (flags << 16u), // Centroid inputs (xor tex2d control) | flags (regs, 16-bit, fragDepth, KILL)
1300+
1301+
0u, // Padding
1302+
};
1303+
1304+
// Copy in the program bytes, swapped
1305+
const u32 start_offset_in_words = fp_metadata.program_start_offset / 4;
1306+
const u32 ucode_length_in_words = fp_metadata.program_ucode_length / 4;
1307+
blob.resize(blob.size() + ucode_length_in_words);
1308+
copy_data_swap_u32(blob.data() + 14, utils::bless<u32>(data_ptr) + start_offset_in_words, ucode_length_in_words);
1309+
//std::memcpy(blob.data() + 14, utils::bless<char>(data_ptr) + fp_metadata.program_start_offset, fp_metadata.program_ucode_length);
1310+
1311+
std::span<u32> fp_binary(blob);
1312+
CgBinaryDisasm fp_disasm(fp_binary);
1313+
fp_disasm.BuildShaderBody(false);
1314+
1315+
m_fragment_disasm->clear();
1316+
m_fragment_disasm->setText(QString::fromStdString(fp_disasm.GetArbShader()));
1317+
}

rpcs3/rpcs3qt/rsx_debugger.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <QListWidget>
1212
#include <QTableWidget>
1313
#include <QTabWidget>
14+
#include <QTextEdit>
1415

1516
#include <memory>
1617

@@ -61,8 +62,8 @@ class rsx_debugger : public QDialog
6162
Buffer* m_buffer_tex;
6263
QLabel* m_enabled_textures_label;
6364

64-
QLabel* m_text_transform_program;
65-
QLabel* m_text_shader_program;
65+
QTextEdit* m_transform_disasm;
66+
QTextEdit* m_fragment_disasm;
6667

6768
u32 m_cur_texture = 0;
6869
u32 m_texture_format_override = 0;
@@ -87,4 +88,7 @@ public Q_SLOTS:
8788

8889
private:
8990
void PerformJump(u32 address);
91+
92+
void GetVertexProgram() const;
93+
void GetFragmentProgram() const;
9094
};

0 commit comments

Comments
 (0)