mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-04 08:22:32 +00:00
devtools: show compute shader regs
This commit is contained in:
parent
eddbe59793
commit
5d3c2eccd1
@ -143,7 +143,7 @@ void DebugStateImpl::PushQueueDump(QueueDump dump) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||||
const AmdGpu::Liverpool::Regs& regs) {
|
const AmdGpu::Liverpool::Regs& regs, bool is_compute) {
|
||||||
std::scoped_lock lock{frame_dump_list_mutex};
|
std::scoped_lock lock{frame_dump_list_mutex};
|
||||||
const auto it = waiting_reg_dumps.find(header_addr);
|
const auto it = waiting_reg_dumps.find(header_addr);
|
||||||
if (it == waiting_reg_dumps.end()) {
|
if (it == waiting_reg_dumps.end()) {
|
||||||
@ -154,15 +154,24 @@ void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
|||||||
waiting_reg_dumps_dbg.erase(waiting_reg_dumps_dbg.find(header_addr));
|
waiting_reg_dumps_dbg.erase(waiting_reg_dumps_dbg.find(header_addr));
|
||||||
auto& dump = frame.regs[header_addr - base_addr];
|
auto& dump = frame.regs[header_addr - base_addr];
|
||||||
dump.regs = regs;
|
dump.regs = regs;
|
||||||
for (int i = 0; i < RegDump::MaxShaderStages; i++) {
|
if (is_compute) {
|
||||||
if (regs.stage_enable.IsStageEnabled(i)) {
|
dump.is_compute = true;
|
||||||
auto stage = regs.ProgramForStage(i);
|
const auto& cs = dump.regs.cs_program;
|
||||||
if (stage->address_lo != 0) {
|
dump.cs_data = ComputerShaderDump{
|
||||||
auto code = stage->Code();
|
.cs_program = cs,
|
||||||
dump.stages[i] = ShaderDump{
|
.code = std::vector<u32>{cs.Code().begin(), cs.Code().end()},
|
||||||
.user_data = *stage,
|
};
|
||||||
.code = std::vector<u32>{code.begin(), code.end()},
|
} else {
|
||||||
};
|
for (int i = 0; i < RegDump::MaxShaderStages; i++) {
|
||||||
|
if (regs.stage_enable.IsStageEnabled(i)) {
|
||||||
|
auto stage = regs.ProgramForStage(i);
|
||||||
|
if (stage->address_lo != 0) {
|
||||||
|
auto code = stage->Code();
|
||||||
|
dump.stages[i] = ShaderDump{
|
||||||
|
.user_data = *stage,
|
||||||
|
.code = std::vector<u32>{code.begin(), code.end()},
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,10 +54,17 @@ struct ShaderDump {
|
|||||||
std::vector<u32> code{};
|
std::vector<u32> code{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ComputerShaderDump {
|
||||||
|
Vulkan::Liverpool::ComputeProgram cs_program{};
|
||||||
|
std::vector<u32> code{};
|
||||||
|
};
|
||||||
|
|
||||||
struct RegDump {
|
struct RegDump {
|
||||||
|
bool is_compute{false};
|
||||||
static constexpr size_t MaxShaderStages = 5;
|
static constexpr size_t MaxShaderStages = 5;
|
||||||
Vulkan::Liverpool::Regs regs{};
|
Vulkan::Liverpool::Regs regs{};
|
||||||
std::array<ShaderDump, MaxShaderStages> stages{};
|
std::array<ShaderDump, MaxShaderStages> stages{};
|
||||||
|
ComputerShaderDump cs_data{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FrameDump {
|
struct FrameDump {
|
||||||
@ -144,7 +151,7 @@ public:
|
|||||||
void PushQueueDump(QueueDump dump);
|
void PushQueueDump(QueueDump dump);
|
||||||
|
|
||||||
void PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
void PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||||
const AmdGpu::Liverpool::Regs& regs);
|
const AmdGpu::Liverpool::Regs& regs, bool is_compute = false);
|
||||||
};
|
};
|
||||||
} // namespace DebugStateType
|
} // namespace DebugStateType
|
||||||
|
|
||||||
|
@ -43,7 +43,16 @@ static std::optional<std::string> exec_cli(const char* cli) {
|
|||||||
namespace Core::Devtools::Widget {
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
void RegView::ProcessShader(int shader_id) {
|
void RegView::ProcessShader(int shader_id) {
|
||||||
auto shader = data.stages[shader_id];
|
std::vector<u32> shader_code;
|
||||||
|
Vulkan::Liverpool::UserData user_data;
|
||||||
|
if (data.is_compute) {
|
||||||
|
shader_code = data.cs_data.code;
|
||||||
|
user_data = data.cs_data.cs_program.user_data;
|
||||||
|
} else {
|
||||||
|
const auto& s = data.stages[shader_id];
|
||||||
|
shader_code = s.code;
|
||||||
|
user_data = s.user_data.user_data;
|
||||||
|
}
|
||||||
|
|
||||||
std::string shader_dis;
|
std::string shader_dis;
|
||||||
|
|
||||||
@ -60,7 +69,7 @@ void RegView::ProcessShader(int shader_id) {
|
|||||||
} else {
|
} else {
|
||||||
cli.replace(pos, src_arg.size(), "\"" + bin_path.string() + "\"");
|
cli.replace(pos, src_arg.size(), "\"" + bin_path.string() + "\"");
|
||||||
Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Write);
|
Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Write);
|
||||||
file.Write(shader.code);
|
file.Write(shader_code);
|
||||||
file.Close();
|
file.Close();
|
||||||
|
|
||||||
auto result = exec_cli(cli.c_str());
|
auto result = exec_cli(cli.c_str());
|
||||||
@ -88,7 +97,7 @@ void RegView::ProcessShader(int shader_id) {
|
|||||||
ShaderCache cache{
|
ShaderCache cache{
|
||||||
.hex_view = hex_view,
|
.hex_view = hex_view,
|
||||||
.dis_view = dis_view,
|
.dis_view = dis_view,
|
||||||
.user_data = shader.user_data.user_data,
|
.user_data = user_data,
|
||||||
};
|
};
|
||||||
shader_decomp.emplace(shader_id, std::move(cache));
|
shader_decomp.emplace(shader_id, std::move(cache));
|
||||||
}
|
}
|
||||||
@ -99,11 +108,48 @@ void RegView::SelectShader(int id) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegView::DrawRegs() {
|
void RegView::DrawComputeRegs() {
|
||||||
|
const auto& cs = data.cs_data.cs_program;
|
||||||
|
|
||||||
|
if (BeginTable("CREGS", 2, ImGuiTableFlags_Borders)) {
|
||||||
|
TableNextRow();
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
DrawValueRowList(
|
||||||
|
"DISPATCH_INITIATOR", cs.dispatch_initiator,
|
||||||
|
"DIM_X", cs.dim_x,
|
||||||
|
"DIM_Y", cs.dim_y,
|
||||||
|
"DIM_Z", cs.dim_z,
|
||||||
|
"START_X", cs.start_x,
|
||||||
|
"START_Y", cs.start_y,
|
||||||
|
"START_Z", cs.start_z,
|
||||||
|
"NUM_THREAD_X.FULL", cs.num_thread_x.full,
|
||||||
|
"NUM_THREAD_X.PARTIAL", cs.num_thread_x.partial,
|
||||||
|
"NUM_THREAD_Y.FULL", cs.num_thread_y.full,
|
||||||
|
"NUM_THREAD_Y.PARTIAL", cs.num_thread_y.partial,
|
||||||
|
"NUM_THREAD_Z.FULL", cs.num_thread_z.full,
|
||||||
|
"NUM_THREAD_Z.PARTIAL", cs.num_thread_z.partial,
|
||||||
|
"MAX_WAVE_ID", cs.max_wave_id,
|
||||||
|
"SETTINGS.NUM_VGPRS", cs.settings.num_vgprs,
|
||||||
|
"SETTINGS.NUM_SGPRS", cs.settings.num_sgprs,
|
||||||
|
"SETTINGS.NUM_USER_REGS", cs.settings.num_user_regs,
|
||||||
|
"SETTINGS.TGID_ENABLE", cs.settings.tgid_enable,
|
||||||
|
"SETTINGS.LDS_DWORDS", cs.settings.lds_dwords,
|
||||||
|
"RESOURCE_LIMITS", cs.resource_limits
|
||||||
|
);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegView::DrawGraphicsRegs() {
|
||||||
const auto& regs = data.regs;
|
const auto& regs = data.regs;
|
||||||
|
|
||||||
if (BeginTable("REGS", 2, ImGuiTableFlags_Borders)) {
|
if (BeginTable("REGS", 2, ImGuiTableFlags_Borders)) {
|
||||||
|
TableNextRow();
|
||||||
|
|
||||||
|
DrawValueRow("Primitive type", regs.primitive_type);
|
||||||
auto& s = regs.screen_scissor;
|
auto& s = regs.screen_scissor;
|
||||||
DrawRow("Scissor", "(%d, %d, %d, %d)", s.top_left_x, s.top_left_y, s.bottom_right_x,
|
DrawRow("Scissor", "(%d, %d, %d, %d)", s.top_left_x, s.top_left_y, s.bottom_right_x,
|
||||||
s.bottom_right_y);
|
s.bottom_right_y);
|
||||||
@ -165,6 +211,18 @@ void RegView::DrawRegs() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DrawRow("Primitive restart", "%X (IDX: %X)", regs.enable_primitive_restart & 1,
|
||||||
|
regs.primitive_restart_index);
|
||||||
|
// clang-format off
|
||||||
|
DrawValueRowList(
|
||||||
|
"Polygon mode", regs.polygon_control.PolyMode(),
|
||||||
|
"Cull mode", regs.polygon_control.CullingMode(),
|
||||||
|
"Clip Space", regs.clipper_control.clip_space,
|
||||||
|
"Front face", regs.polygon_control.front_face,
|
||||||
|
"Num Samples", regs.aa_config.NumSamples()
|
||||||
|
);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
EndTable();
|
EndTable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,25 +268,33 @@ void RegView::SetData(DebugStateType::RegDump _data, const std::string& base_tit
|
|||||||
this->title = fmt::format("{}/Batch {}", base_title, batch_id);
|
this->title = fmt::format("{}/Batch {}", base_title, batch_id);
|
||||||
// clear cache
|
// clear cache
|
||||||
shader_decomp.clear();
|
shader_decomp.clear();
|
||||||
const auto& regs = data.regs;
|
if (data.is_compute) {
|
||||||
if (selected_shader >= 0 && !regs.stage_enable.IsStageEnabled(selected_shader)) {
|
selected_shader = -2;
|
||||||
selected_shader = -1;
|
last_selected_cb = -1;
|
||||||
}
|
|
||||||
if (default_reg_popup.open) {
|
|
||||||
default_reg_popup.open = false;
|
default_reg_popup.open = false;
|
||||||
if (last_selected_cb == depth_id) {
|
ProcessShader(-2);
|
||||||
const auto& has_depth =
|
} else {
|
||||||
regs.depth_buffer.Address() != 0 && regs.depth_control.depth_enable;
|
const auto& regs = data.regs;
|
||||||
if (has_depth) {
|
if (selected_shader >= 0 && !regs.stage_enable.IsStageEnabled(selected_shader)) {
|
||||||
default_reg_popup.SetData(title, regs.depth_buffer, regs.depth_control);
|
selected_shader = -1;
|
||||||
default_reg_popup.open = true;
|
}
|
||||||
}
|
if (default_reg_popup.open) {
|
||||||
} else if (last_selected_cb >= 0 && last_selected_cb < AmdGpu::Liverpool::NumColorBuffers) {
|
default_reg_popup.open = false;
|
||||||
const auto& buffer = regs.color_buffers[last_selected_cb];
|
if (last_selected_cb == depth_id) {
|
||||||
const bool has_cb = buffer && regs.color_target_mask.GetMask(last_selected_cb);
|
const auto& has_depth =
|
||||||
if (has_cb) {
|
regs.depth_buffer.Address() != 0 && regs.depth_control.depth_enable;
|
||||||
default_reg_popup.SetData(title, buffer, last_selected_cb);
|
if (has_depth) {
|
||||||
default_reg_popup.open = true;
|
default_reg_popup.SetData(title, regs.depth_buffer, regs.depth_control);
|
||||||
|
default_reg_popup.open = true;
|
||||||
|
}
|
||||||
|
} else if (last_selected_cb >= 0 &&
|
||||||
|
last_selected_cb < AmdGpu::Liverpool::NumColorBuffers) {
|
||||||
|
const auto& buffer = regs.color_buffers[last_selected_cb];
|
||||||
|
const bool has_cb = buffer && regs.color_target_mask.GetMask(last_selected_cb);
|
||||||
|
if (has_cb) {
|
||||||
|
default_reg_popup.SetData(title, buffer, last_selected_cb);
|
||||||
|
default_reg_popup.open = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -267,7 +333,8 @@ void RegView::Draw() {
|
|||||||
EndMenuBar();
|
EndMenuBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BeginChild("STAGES", {},
|
if (!data.is_compute &&
|
||||||
|
BeginChild("STAGES", {},
|
||||||
ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeY)) {
|
ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_AutoResizeY)) {
|
||||||
for (int i = 0; i < DebugStateType::RegDump::MaxShaderStages; i++) {
|
for (int i = 0; i < DebugStateType::RegDump::MaxShaderStages; i++) {
|
||||||
if (data.regs.stage_enable.IsStageEnabled(i)) {
|
if (data.regs.stage_enable.IsStageEnabled(i)) {
|
||||||
@ -331,7 +398,11 @@ void RegView::Draw() {
|
|||||||
if (show_registers) {
|
if (show_registers) {
|
||||||
snprintf(name, sizeof(name), "Regs###reg_dump_%d/regs", id);
|
snprintf(name, sizeof(name), "Regs###reg_dump_%d/regs", id);
|
||||||
if (Begin(name, &show_registers)) {
|
if (Begin(name, &show_registers)) {
|
||||||
DrawRegs();
|
if (data.is_compute) {
|
||||||
|
DrawComputeRegs();
|
||||||
|
} else {
|
||||||
|
DrawGraphicsRegs();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
End();
|
End();
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,9 @@ class RegView {
|
|||||||
|
|
||||||
void SelectShader(int shader_id);
|
void SelectShader(int shader_id);
|
||||||
|
|
||||||
void DrawRegs();
|
void DrawComputeRegs();
|
||||||
|
|
||||||
|
void DrawGraphicsRegs();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool open = false;
|
bool open = false;
|
||||||
|
@ -446,7 +446,8 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||||||
regs.cs_program.dim_z = dispatch_direct->dim_z;
|
regs.cs_program.dim_z = dispatch_direct->dim_z;
|
||||||
regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator;
|
regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator;
|
||||||
if (DebugState.DumpingCurrentReg()) {
|
if (DebugState.DumpingCurrentReg()) {
|
||||||
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs);
|
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
||||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||||
@ -463,7 +464,8 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||||||
const auto ib_address = mapped_queues[GfxQueueId].indirect_args_addr;
|
const auto ib_address = mapped_queues[GfxQueueId].indirect_args_addr;
|
||||||
const auto size = sizeof(PM4CmdDispatchIndirect::GroupDimensions);
|
const auto size = sizeof(PM4CmdDispatchIndirect::GroupDimensions);
|
||||||
if (DebugState.DumpingCurrentReg()) {
|
if (DebugState.DumpingCurrentReg()) {
|
||||||
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs);
|
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
||||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||||
@ -645,7 +647,7 @@ Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb, int vqid) {
|
|||||||
regs.cs_program.dim_z = dispatch_direct->dim_z;
|
regs.cs_program.dim_z = dispatch_direct->dim_z;
|
||||||
regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator;
|
regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator;
|
||||||
if (DebugState.DumpingCurrentReg()) {
|
if (DebugState.DumpingCurrentReg()) {
|
||||||
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs);
|
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs, true);
|
||||||
}
|
}
|
||||||
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
||||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||||
|
Loading…
Reference in New Issue
Block a user