mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-04 08:22:32 +00:00
devtools: pm4 - show markers
This commit is contained in:
parent
66f1bb937f
commit
67f9bd4822
@ -355,6 +355,8 @@ set(DEV_TOOLS src/core/devtools/layer.cpp
|
|||||||
src/core/devtools/widget/frame_dump.h
|
src/core/devtools/widget/frame_dump.h
|
||||||
src/core/devtools/widget/frame_graph.cpp
|
src/core/devtools/widget/frame_graph.cpp
|
||||||
src/core/devtools/widget/frame_graph.h
|
src/core/devtools/widget/frame_graph.h
|
||||||
|
src/core/devtools/widget/imgui_memory_editor.h
|
||||||
|
src/core/devtools/widget/types.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(COMMON src/common/logging/backend.cpp
|
set(COMMON src/common/logging/backend.cpp
|
||||||
|
@ -42,6 +42,7 @@ struct QueueDump {
|
|||||||
u32 submit_num;
|
u32 submit_num;
|
||||||
u32 num2; // acb: queue_num; else: buffer_in_submit
|
u32 num2; // acb: queue_num; else: buffer_in_submit
|
||||||
std::vector<u32> data;
|
std::vector<u32> data;
|
||||||
|
uintptr_t base_addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FrameDump {
|
struct FrameDump {
|
||||||
|
@ -140,26 +140,50 @@ void L::DrawSimple() {
|
|||||||
Text("Frame time: %.3f ms (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
|
Text("Frame time: %.3f ms (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void LoadSettings(const char* line) {
|
||||||
|
int i;
|
||||||
|
float f;
|
||||||
|
if (sscanf(line, "fps_scale=%f", &f) == 1) {
|
||||||
|
fps_scale = f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sscanf(line, "show_advanced_debug=%d", &i) == 1) {
|
||||||
|
show_advanced_debug = i != 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sscanf(line, "show_frame_graph=%d", &i) == 1) {
|
||||||
|
frame_graph.is_open = i != 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sscanf(line, "dump_frame_count=%d", &i) == 1) {
|
||||||
|
dump_frame_count = i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void L::SetupSettings() {
|
void L::SetupSettings() {
|
||||||
frame_graph.is_open = true;
|
frame_graph.is_open = true;
|
||||||
|
|
||||||
|
using SettingLoader = void (*)(const char*);
|
||||||
|
|
||||||
ImGuiSettingsHandler handler{};
|
ImGuiSettingsHandler handler{};
|
||||||
handler.TypeName = "DevtoolsLayer";
|
handler.TypeName = "DevtoolsLayer";
|
||||||
handler.TypeHash = ImHashStr(handler.TypeName);
|
handler.TypeHash = ImHashStr(handler.TypeName);
|
||||||
handler.ReadOpenFn = [](ImGuiContext*, ImGuiSettingsHandler*, const char* name) {
|
handler.ReadOpenFn = [](ImGuiContext*, ImGuiSettingsHandler*, const char* name) {
|
||||||
return std::string_view("Data") == name ? (void*)1 : nullptr;
|
if (std::string_view("Data") == name) {
|
||||||
|
static_assert(std::is_same_v<decltype(&LoadSettings), SettingLoader>);
|
||||||
|
return (void*)&LoadSettings;
|
||||||
|
}
|
||||||
|
if (std::string_view("CmdList") == name) {
|
||||||
|
static_assert(
|
||||||
|
std::is_same_v<decltype(&Widget::CmdListViewer::LoadConfig), SettingLoader>);
|
||||||
|
return (void*)&Widget::CmdListViewer::LoadConfig;
|
||||||
|
}
|
||||||
|
return (void*)nullptr;
|
||||||
};
|
};
|
||||||
handler.ReadLineFn = [](ImGuiContext*, ImGuiSettingsHandler*, void*, const char* line) {
|
handler.ReadLineFn = [](ImGuiContext*, ImGuiSettingsHandler*, void* handle, const char* line) {
|
||||||
int v;
|
if (handle != nullptr) {
|
||||||
float f;
|
reinterpret_cast<SettingLoader>(handle)(line);
|
||||||
if (sscanf(line, "fps_scale=%f", &f) == 1) {
|
|
||||||
fps_scale = f;
|
|
||||||
} else if (sscanf(line, "show_advanced_debug=%d", &v) == 1) {
|
|
||||||
show_advanced_debug = v != 0;
|
|
||||||
} else if (sscanf(line, "show_frame_graph=%d", &v) == 1) {
|
|
||||||
frame_graph.is_open = v != 0;
|
|
||||||
} else if (sscanf(line, "dump_frame_count=%d", &v) == 1) {
|
|
||||||
dump_frame_count = v;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
handler.WriteAllFn = [](ImGuiContext*, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) {
|
handler.WriteAllFn = [](ImGuiContext*, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) {
|
||||||
@ -169,6 +193,9 @@ void L::SetupSettings() {
|
|||||||
buf->appendf("show_frame_graph=%d\n", frame_graph.is_open);
|
buf->appendf("show_frame_graph=%d\n", frame_graph.is_open);
|
||||||
buf->appendf("dump_frame_count=%d\n", dump_frame_count);
|
buf->appendf("dump_frame_count=%d\n", dump_frame_count);
|
||||||
buf->append("\n");
|
buf->append("\n");
|
||||||
|
buf->appendf("[%s][CmdList]\n", handler->TypeName);
|
||||||
|
Widget::CmdListViewer::SerializeConfig(buf);
|
||||||
|
buf->append("\n");
|
||||||
};
|
};
|
||||||
AddSettingsHandler(&handler);
|
AddSettingsHandler(&handler);
|
||||||
|
|
||||||
|
@ -32,6 +32,26 @@ const char* GetOpCodeName(u32 op);
|
|||||||
|
|
||||||
namespace Core::Devtools::Widget {
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
static bool group_batches = false;
|
||||||
|
static bool show_markers = true;
|
||||||
|
|
||||||
|
void CmdListViewer::LoadConfig(const char* line) {
|
||||||
|
int i;
|
||||||
|
if (sscanf(line, "group_batches=%d", &i) == 1) {
|
||||||
|
group_batches = i != 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sscanf(line, "show_markers=%d", &i) == 1) {
|
||||||
|
show_markers = i != 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CmdListViewer::SerializeConfig(ImGuiTextBuffer* buf) {
|
||||||
|
buf->appendf("group_batches=%d\n", group_batches);
|
||||||
|
buf->appendf("show_markers=%d\n", show_markers);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename HdrType>
|
template <typename HdrType>
|
||||||
static HdrType GetNext(HdrType this_pm4, uint32_t n) {
|
static HdrType GetNext(HdrType this_pm4, uint32_t n) {
|
||||||
HdrType curr_pm4 = this_pm4;
|
HdrType curr_pm4 = this_pm4;
|
||||||
@ -783,33 +803,32 @@ static void ParseZInfo(u32 value) {
|
|||||||
void CmdListViewer::OnNop(AmdGpu::PM4Type3Header const* header, u32 const* body) {
|
void CmdListViewer::OnNop(AmdGpu::PM4Type3Header const* header, u32 const* body) {
|
||||||
using namespace std::string_view_literals;
|
using namespace std::string_view_literals;
|
||||||
|
|
||||||
enum class NOP_PAYLOAD : u32 {
|
#define NOP_PAYLOAD \
|
||||||
ACB_SUBMIT_MRK = 0x68750013,
|
P(PUSH_MARKER, 0x68750001) \
|
||||||
ALLOC_ALIGN8 = 0x68753000,
|
P(POP_MARKER, 0x68750002) \
|
||||||
PUSH_MARKER = 0x68750001,
|
P(SET_MARKER, 0x68750003) \
|
||||||
SET_VSHARP = 0x68750004,
|
P(SET_VSHARP, 0x68750004) \
|
||||||
SET_TSHARP = 0x68750005,
|
P(SET_TSHARP, 0x68750005) \
|
||||||
SET_SSHARP = 0x68750006,
|
P(SET_SSHARP, 0x68750006) \
|
||||||
SET_USER_DATA = 0x6875000d,
|
P(ACB_SUBMIT_MRK, 0x68750013) \
|
||||||
};
|
P(SET_USER_DATA, 0x6875000D) \
|
||||||
auto get_noppayload_text = [](NOP_PAYLOAD const nop_payload) {
|
P(PATCHED_FLIP, 0x68750776) \
|
||||||
|
P(PREPARE_FLIP, 0x68750777) \
|
||||||
|
P(PREPARE_FLIP_LABEL, 0x68750778) \
|
||||||
|
P(PREPARE_FLIP_INTERRUPT, 0x68750780) \
|
||||||
|
P(PREPARE_FLIP_INTERRUPT_LABEL, 0x68750781) \
|
||||||
|
P(ALLOC_ALIGN8, 0x68753000)
|
||||||
|
|
||||||
|
auto get_nop_payload_text = [](u32 const nop_payload) {
|
||||||
switch (nop_payload) {
|
switch (nop_payload) {
|
||||||
case NOP_PAYLOAD::ACB_SUBMIT_MRK:
|
#define P(name, value) \
|
||||||
return "ACB_SUBMIT_MRK"sv;
|
case value: \
|
||||||
case NOP_PAYLOAD::ALLOC_ALIGN8:
|
return #name##sv;
|
||||||
return "ALLOC_ALIGN8"sv;
|
NOP_PAYLOAD
|
||||||
case NOP_PAYLOAD::PUSH_MARKER:
|
#undef P
|
||||||
return "PUSH_MARKER"sv;
|
default:
|
||||||
case NOP_PAYLOAD::SET_VSHARP:
|
return ""sv;
|
||||||
return "SET_VSHARP"sv;
|
|
||||||
case NOP_PAYLOAD::SET_TSHARP:
|
|
||||||
return "SET_TSHARP"sv;
|
|
||||||
case NOP_PAYLOAD::SET_SSHARP:
|
|
||||||
return "SET_SSHARP"sv;
|
|
||||||
case NOP_PAYLOAD::SET_USER_DATA:
|
|
||||||
return "SET_USER_DATA"sv;
|
|
||||||
}
|
}
|
||||||
return ""sv;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Separator();
|
Separator();
|
||||||
@ -822,7 +841,7 @@ void CmdListViewer::OnNop(AmdGpu::PM4Type3Header const* header, u32 const* body)
|
|||||||
for (unsigned i = 0; i < pkt->header.count + 1; ++i) {
|
for (unsigned i = 0; i < pkt->header.count + 1; ++i) {
|
||||||
Text("%02X: %08X", i, payload[i]);
|
Text("%02X: %08X", i, payload[i]);
|
||||||
if ((payload[i] & 0xffff0000) == 0x68750000) {
|
if ((payload[i] & 0xffff0000) == 0x68750000) {
|
||||||
const auto& e = get_noppayload_text((NOP_PAYLOAD)payload[i]);
|
const auto& e = get_nop_payload_text(payload[i]);
|
||||||
if (!e.empty()) {
|
if (!e.empty()) {
|
||||||
SameLine();
|
SameLine();
|
||||||
Text("(%s)", e.data());
|
Text("(%s)", e.data());
|
||||||
@ -1025,20 +1044,30 @@ void CmdListViewer::OnDispatch(AmdGpu::PM4Type3Header const* header, u32 const*
|
|||||||
EndGroup();
|
EndGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
CmdListViewer::CmdListViewer(FrameDumpViewer* parent, const std::vector<u32>& cmd_list)
|
CmdListViewer::CmdListViewer(const std::vector<u32>& cmd_list, uintptr_t base_addr,
|
||||||
: parent(parent) {
|
std::string name)
|
||||||
|
: base_addr(base_addr), name(std::move(name)) {
|
||||||
using namespace AmdGpu;
|
using namespace AmdGpu;
|
||||||
|
|
||||||
cmdb_addr = (uintptr_t)cmd_list.data();
|
cmdb_addr = (uintptr_t)cmd_list.data();
|
||||||
cmdb_size = cmd_list.size() * sizeof(u32);
|
cmdb_size = cmd_list.size() * sizeof(u32);
|
||||||
|
|
||||||
|
cmdb_view_name = fmt::format("[GFX] Command buffer {}###cmdview_hex_{}", this->name, cmdb_addr);
|
||||||
|
cmdb_view.Open = false;
|
||||||
|
cmdb_view.ReadOnly = true;
|
||||||
|
|
||||||
auto const* pm4_hdr = reinterpret_cast<PM4Header const*>(cmdb_addr);
|
auto const* pm4_hdr = reinterpret_cast<PM4Header const*>(cmdb_addr);
|
||||||
|
|
||||||
size_t processed_size = 0;
|
size_t processed_size = 0;
|
||||||
size_t prev_offset = 0;
|
size_t prev_offset = 0;
|
||||||
|
u32 batch_id = 0;
|
||||||
|
|
||||||
std::string marker{};
|
std::string marker{};
|
||||||
|
|
||||||
|
if (cmdb_size > 0) {
|
||||||
|
events.emplace_back(BatchBegin{.id = 0});
|
||||||
|
}
|
||||||
|
|
||||||
while (processed_size < cmdb_size) {
|
while (processed_size < cmdb_size) {
|
||||||
auto* next_pm4_hdr = GetNext(pm4_hdr, 1);
|
auto* next_pm4_hdr = GetNext(pm4_hdr, 1);
|
||||||
auto processed_len =
|
auto processed_len =
|
||||||
@ -1048,20 +1077,30 @@ CmdListViewer::CmdListViewer(FrameDumpViewer* parent, const std::vector<u32>& cm
|
|||||||
if (pm4_hdr->type == PM4Type3Header::TYPE) {
|
if (pm4_hdr->type == PM4Type3Header::TYPE) {
|
||||||
|
|
||||||
auto const* pm4_t3 = reinterpret_cast<PM4Type3Header const*>(pm4_hdr);
|
auto const* pm4_t3 = reinterpret_cast<PM4Type3Header const*>(pm4_hdr);
|
||||||
|
auto opcode = pm4_t3->opcode;
|
||||||
|
|
||||||
if (pm4_t3->opcode == PM4ItOpcode::Nop) {
|
if (opcode == PM4ItOpcode::Nop) {
|
||||||
auto const* it_body = reinterpret_cast<uint32_t const*>(pm4_hdr + 1);
|
auto const* it_body = reinterpret_cast<uint32_t const*>(pm4_hdr + 1);
|
||||||
if (it_body[0] == 0x68750001) {
|
switch (it_body[0]) {
|
||||||
|
case PM4CmdNop::PayloadType::DebugSetMarker:
|
||||||
marker = std::string{(char*)&it_body[1]};
|
marker = std::string{(char*)&it_body[1]};
|
||||||
|
break;
|
||||||
|
case PM4CmdNop::PayloadType::DebugMarkerPush:
|
||||||
|
events.emplace_back(PushMarker{
|
||||||
|
.name = std::string{(char*)&it_body[1]},
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case PM4CmdNop::PayloadType::DebugMarkerPop:
|
||||||
|
events.emplace_back(PopMarker{});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pm4_t3->opcode == PM4ItOpcode::DispatchDirect ||
|
if (opcode == PM4ItOpcode::DispatchDirect || opcode == PM4ItOpcode::DispatchIndirect ||
|
||||||
pm4_t3->opcode == PM4ItOpcode::DispatchIndirect ||
|
opcode == PM4ItOpcode::DrawIndex2 || opcode == PM4ItOpcode::DrawIndexAuto ||
|
||||||
pm4_t3->opcode == PM4ItOpcode::DrawIndex2 ||
|
opcode == PM4ItOpcode::DrawIndexOffset2 || opcode == PM4ItOpcode::DrawIndexIndirect
|
||||||
pm4_t3->opcode == PM4ItOpcode::DrawIndexAuto ||
|
|
||||||
pm4_t3->opcode == PM4ItOpcode::DrawIndexOffset2 ||
|
|
||||||
pm4_t3->opcode == PM4ItOpcode::DrawIndexIndirect
|
|
||||||
// ...
|
// ...
|
||||||
) {
|
) {
|
||||||
// All these commands are terminated by NOP at the end, so
|
// All these commands are terminated by NOP at the end, so
|
||||||
@ -1071,15 +1110,17 @@ CmdListViewer::CmdListViewer(FrameDumpViewer* parent, const std::vector<u32>& cm
|
|||||||
// processed_len += nop_len;
|
// processed_len += nop_len;
|
||||||
// processed_size += nop_len;
|
// processed_size += nop_len;
|
||||||
|
|
||||||
batches.emplace_back(BatchInfo{
|
events.emplace_back(BatchInfo{
|
||||||
marker,
|
.id = batch_id++,
|
||||||
prev_offset,
|
.marker = marker,
|
||||||
processed_size,
|
.start_addr = prev_offset,
|
||||||
processed_size - processed_len,
|
.end_addr = processed_size,
|
||||||
pm4_t3->opcode,
|
.command_addr = processed_size - processed_len,
|
||||||
|
.type = opcode,
|
||||||
});
|
});
|
||||||
prev_offset = processed_size;
|
prev_offset = processed_size;
|
||||||
marker.clear();
|
marker.clear();
|
||||||
|
events.emplace_back(BatchBegin{.id = batch_id});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1088,18 +1129,30 @@ CmdListViewer::CmdListViewer(FrameDumpViewer* parent, const std::vector<u32>& cm
|
|||||||
|
|
||||||
// state batch (last)
|
// state batch (last)
|
||||||
if (processed_size - prev_offset > 0) {
|
if (processed_size - prev_offset > 0) {
|
||||||
batches.emplace_back(BatchInfo{
|
events.emplace_back(BatchInfo{
|
||||||
marker,
|
.id = batch_id++,
|
||||||
prev_offset,
|
.marker = marker,
|
||||||
processed_size,
|
.start_addr = prev_offset,
|
||||||
0,
|
.end_addr = processed_size,
|
||||||
static_cast<PM4ItOpcode>(0xFF),
|
.command_addr = 0,
|
||||||
|
.type = static_cast<PM4ItOpcode>(0xFF),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (!events.empty() && std::holds_alternative<BatchBegin>(events.back())) {
|
||||||
|
events.pop_back();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CmdListViewer::Draw() {
|
void CmdListViewer::Draw() {
|
||||||
|
const auto& ctx = *GetCurrentContext();
|
||||||
|
|
||||||
|
PushID(name.c_str());
|
||||||
if (BeginChild("cmd_queue", {})) {
|
if (BeginChild("cmd_queue", {})) {
|
||||||
|
|
||||||
|
Checkbox("Group batches", &group_batches);
|
||||||
|
SameLine();
|
||||||
|
Checkbox("Show markers", &show_markers);
|
||||||
|
|
||||||
char queue_name[32]{};
|
char queue_name[32]{};
|
||||||
if (vqid < 254) {
|
if (vqid < 254) {
|
||||||
std::snprintf(queue_name, sizeof(queue_name), "%s %d", vqid > 254 ? "GFX" : "ASC",
|
std::snprintf(queue_name, sizeof(queue_name), "%s %d", vqid > 254 ? "GFX" : "ASC",
|
||||||
@ -1111,113 +1164,209 @@ void CmdListViewer::Draw() {
|
|||||||
Text("queue : %s", queue_name);
|
Text("queue : %s", queue_name);
|
||||||
Text("base addr: %08llX", cmdb_addr);
|
Text("base addr: %08llX", cmdb_addr);
|
||||||
SameLine();
|
SameLine();
|
||||||
if (SmallButton(">")) {
|
if (SmallButton("Memory >")) {
|
||||||
parent->cmdb_view.Open ^= true;
|
cmdb_view.Open ^= true;
|
||||||
}
|
}
|
||||||
Text("size : %04llX", cmdb_size);
|
Text("size : %04llX", cmdb_size);
|
||||||
Separator();
|
Separator();
|
||||||
|
|
||||||
char batch_hdr[128];
|
if (TreeNode("Batches")) {
|
||||||
for (int batch_id = 0; batch_id < batches.size(); ++batch_id) {
|
int tree_depth = 0;
|
||||||
auto processed_size = 0ull;
|
int tree_depth_show = 0;
|
||||||
auto const* pm4_hdr =
|
|
||||||
reinterpret_cast<PM4Header const*>(cmdb_addr + batches[batch_id].start_addr);
|
|
||||||
|
|
||||||
sprintf(batch_hdr, "%08llX: batch-%03d | %s", cmdb_addr + batches[batch_id].start_addr,
|
u32 last_batch_id = ~0u;
|
||||||
batch_id, batches[batch_id].marker.c_str());
|
if (!events.empty() && std::holds_alternative<BatchInfo>(events.back())) {
|
||||||
|
last_batch_id = std::get<BatchInfo>(events.back()).id;
|
||||||
if (batch_id == batch_bp) { // highlight batch at breakpoint
|
|
||||||
PushStyleColor(ImGuiCol_Header, ImVec4{1.0f, 0.5f, 0.5f, 0.5f});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (batches[batch_id].type == static_cast<AmdGpu::PM4ItOpcode>(0xFF) ||
|
u32 batch_id = ~0u;
|
||||||
CollapsingHeader(batch_hdr)) {
|
s32 current_highlight_batch = -1;
|
||||||
auto const batch_sz = batches[batch_id].end_addr - batches[batch_id].start_addr;
|
|
||||||
while (processed_size < batch_sz) {
|
|
||||||
AmdGpu::PM4ItOpcode op{0xFFu};
|
|
||||||
|
|
||||||
if (pm4_hdr->type == AmdGpu::PM4Type3Header::TYPE) {
|
for (const auto& event : events) {
|
||||||
auto const* pm4_t3 =
|
auto processed_size = 0ull;
|
||||||
reinterpret_cast<AmdGpu::PM4Type3Header const*>(pm4_hdr);
|
|
||||||
op = pm4_t3->opcode;
|
|
||||||
|
|
||||||
static char header_name[128];
|
if (show_markers) {
|
||||||
sprintf(header_name, "%08llX: %s",
|
if (std::holds_alternative<PushMarker>(event)) {
|
||||||
cmdb_addr + batches[batch_id].start_addr + processed_size,
|
if (tree_depth_show >= tree_depth) {
|
||||||
Gcn::GetOpCodeName((u32)op));
|
auto& marker = std::get<PushMarker>(event);
|
||||||
|
bool show = TreeNode(&event, "%s", marker.name.c_str());
|
||||||
if (TreeNode(header_name)) {
|
if (show) {
|
||||||
bool just_opened = IsItemToggledOpen();
|
tree_depth_show++;
|
||||||
if (BeginTable("split", 1)) {
|
|
||||||
TableNextColumn();
|
|
||||||
Text("size: %d", pm4_hdr->count + 1);
|
|
||||||
|
|
||||||
if (just_opened) {
|
|
||||||
// Editor
|
|
||||||
parent->cmdb_view.GotoAddrAndHighlight(
|
|
||||||
reinterpret_cast<size_t>(pm4_hdr) - cmdb_addr,
|
|
||||||
reinterpret_cast<size_t>(pm4_hdr) - cmdb_addr +
|
|
||||||
(pm4_hdr->count + 2) * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto const* it_body =
|
|
||||||
reinterpret_cast<uint32_t const*>(pm4_hdr + 1);
|
|
||||||
|
|
||||||
switch (op) {
|
|
||||||
case AmdGpu::PM4ItOpcode::Nop: {
|
|
||||||
OnNop(pm4_t3, it_body);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AmdGpu::PM4ItOpcode::SetBase: {
|
|
||||||
OnSetBase(pm4_t3, it_body);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AmdGpu::PM4ItOpcode::SetContextReg: {
|
|
||||||
OnSetContextReg(pm4_t3, it_body);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AmdGpu::PM4ItOpcode::SetShReg: {
|
|
||||||
OnSetShReg(pm4_t3, it_body);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AmdGpu::PM4ItOpcode::DispatchDirect: {
|
|
||||||
OnDispatch(pm4_t3, it_body);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
auto const* payload = &it_body[0];
|
|
||||||
for (unsigned i = 0; i < pm4_hdr->count + 1; ++i) {
|
|
||||||
Text("%02X: %08X", i, payload[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EndTable();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
tree_depth++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (std::holds_alternative<PopMarker>(event)) {
|
||||||
|
if (tree_depth_show >= tree_depth) {
|
||||||
|
tree_depth_show--;
|
||||||
TreePop();
|
TreePop();
|
||||||
}
|
}
|
||||||
} else {
|
tree_depth--;
|
||||||
Text("<UNK PACKET>");
|
continue;
|
||||||
|
}
|
||||||
|
if (tree_depth_show < tree_depth) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::holds_alternative<BatchBegin>(event)) {
|
||||||
|
batch_id = std::get<BatchBegin>(event).id;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!std::holds_alternative<BatchInfo>(event)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& batch = std::get<BatchInfo>(event);
|
||||||
|
auto const* pm4_hdr =
|
||||||
|
reinterpret_cast<PM4Header const*>(cmdb_addr + batch.start_addr);
|
||||||
|
|
||||||
|
char batch_hdr[128];
|
||||||
|
if (batch.type == static_cast<AmdGpu::PM4ItOpcode>(0xFF)) {
|
||||||
|
snprintf(batch_hdr, sizeof(batch_hdr), "State batch");
|
||||||
|
} else if (!batch.marker.empty()) {
|
||||||
|
snprintf(batch_hdr, sizeof(batch_hdr), "%08llX: batch-%03d | %s",
|
||||||
|
cmdb_addr + batch.start_addr, batch.id, batch.marker.c_str());
|
||||||
|
} else {
|
||||||
|
snprintf(batch_hdr, sizeof(batch_hdr), "%08llX: batch-%03d",
|
||||||
|
cmdb_addr + batch.start_addr, batch.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (batch.id == batch_bp) { // highlight batch at breakpoint
|
||||||
|
PushStyleColor(ImGuiCol_Header, ImVec4{1.0f, 0.5f, 0.5f, 0.5f});
|
||||||
|
}
|
||||||
|
if (batch.id == highlight_batch) {
|
||||||
|
PushStyleColor(ImGuiCol_Text, ImVec4{1.0f, 0.7f, 0.7f, 1.0f});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!group_batches || CollapsingHeader(batch_hdr)) {
|
||||||
|
auto bb = ctx.LastItemData.Rect;
|
||||||
|
if (group_batches) {
|
||||||
|
Indent();
|
||||||
|
}
|
||||||
|
auto const batch_sz = batch.end_addr - batch.start_addr;
|
||||||
|
|
||||||
|
while (processed_size < batch_sz) {
|
||||||
|
AmdGpu::PM4ItOpcode op{0xFFu};
|
||||||
|
|
||||||
|
if (pm4_hdr->type == AmdGpu::PM4Type3Header::TYPE) {
|
||||||
|
auto const* pm4_t3 =
|
||||||
|
reinterpret_cast<AmdGpu::PM4Type3Header const*>(pm4_hdr);
|
||||||
|
op = pm4_t3->opcode;
|
||||||
|
|
||||||
|
char header_name[128];
|
||||||
|
sprintf(header_name, "%08llX: %s",
|
||||||
|
cmdb_addr + batch.start_addr + processed_size,
|
||||||
|
Gcn::GetOpCodeName((u32)op));
|
||||||
|
|
||||||
|
if (TreeNode(header_name)) {
|
||||||
|
bool just_opened = IsItemToggledOpen();
|
||||||
|
if (BeginTable("split", 1)) {
|
||||||
|
TableNextColumn();
|
||||||
|
Text("size: %d", pm4_hdr->count + 1);
|
||||||
|
|
||||||
|
if (just_opened) {
|
||||||
|
// Editor
|
||||||
|
cmdb_view.GotoAddrAndHighlight(
|
||||||
|
reinterpret_cast<size_t>(pm4_hdr) - cmdb_addr,
|
||||||
|
reinterpret_cast<size_t>(pm4_hdr) - cmdb_addr +
|
||||||
|
(pm4_hdr->count + 2) * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const* it_body =
|
||||||
|
reinterpret_cast<uint32_t const*>(pm4_hdr + 1);
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case AmdGpu::PM4ItOpcode::Nop: {
|
||||||
|
OnNop(pm4_t3, it_body);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AmdGpu::PM4ItOpcode::SetBase: {
|
||||||
|
OnSetBase(pm4_t3, it_body);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AmdGpu::PM4ItOpcode::SetContextReg: {
|
||||||
|
OnSetContextReg(pm4_t3, it_body);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AmdGpu::PM4ItOpcode::SetShReg: {
|
||||||
|
OnSetShReg(pm4_t3, it_body);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AmdGpu::PM4ItOpcode::DispatchDirect: {
|
||||||
|
OnDispatch(pm4_t3, it_body);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
auto const* payload = &it_body[0];
|
||||||
|
for (unsigned i = 0; i < pm4_hdr->count + 1; ++i) {
|
||||||
|
Text("%02X: %08X", i, payload[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EndTable();
|
||||||
|
}
|
||||||
|
TreePop();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Text("<UNK PACKET>");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const* next_pm4_hdr = GetNext(pm4_hdr, 1);
|
||||||
|
auto const processed_len = reinterpret_cast<uintptr_t>(next_pm4_hdr) -
|
||||||
|
reinterpret_cast<uintptr_t>(pm4_hdr);
|
||||||
|
pm4_hdr = next_pm4_hdr;
|
||||||
|
processed_size += processed_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto const* next_pm4_hdr = GetNext(pm4_hdr, 1);
|
if (group_batches) {
|
||||||
auto const processed_len = reinterpret_cast<uintptr_t>(next_pm4_hdr) -
|
Unindent();
|
||||||
reinterpret_cast<uintptr_t>(pm4_hdr);
|
};
|
||||||
pm4_hdr = next_pm4_hdr;
|
bb = {{0.0f, bb.Max.y}, ctx.LastItemData.Rect.Max};
|
||||||
processed_size += processed_len;
|
if (bb.Contains(ctx.IO.MousePos)) {
|
||||||
|
current_highlight_batch = batch.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (batch.id == highlight_batch) {
|
||||||
|
PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (batch.id == batch_bp) {
|
||||||
|
PopStyleColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (batch.id == last_batch_id) {
|
||||||
|
Separator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (batch_id == batch_bp) {
|
highlight_batch = current_highlight_batch;
|
||||||
PopStyleColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (batch_id == batches.size() - 2) {
|
TreePop();
|
||||||
Separator();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EndChild();
|
EndChild();
|
||||||
|
PopID();
|
||||||
|
|
||||||
|
if (cmdb_view.Open) {
|
||||||
|
MemoryEditor::Sizes s;
|
||||||
|
cmdb_view.CalcSizes(s, cmdb_size, cmdb_addr);
|
||||||
|
SetNextWindowSize({s.WindowWidth, s.WindowWidth * 0.6f}, ImGuiCond_FirstUseEver);
|
||||||
|
SetNextWindowSizeConstraints({0.0f}, {s.WindowWidth, FLT_MAX});
|
||||||
|
if (Begin(cmdb_view_name.c_str(), &cmdb_view.Open, ImGuiWindowFlags_NoScrollbar)) {
|
||||||
|
cmdb_view.DrawContents((void*)cmdb_addr, cmdb_size, base_addr);
|
||||||
|
if (cmdb_view.ContentsWidthChanged) {
|
||||||
|
cmdb_view.CalcSizes(s, cmdb_size, cmdb_addr);
|
||||||
|
SetWindowSize({s.WindowWidth, s.WindowWidth * 0.6f});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Devtools::Widget
|
} // namespace Core::Devtools::Widget
|
@ -6,8 +6,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
#include "imgui_memory_editor.h"
|
||||||
|
#include "types.h"
|
||||||
#include "video_core/buffer_cache/buffer_cache.h"
|
#include "video_core/buffer_cache/buffer_cache.h"
|
||||||
|
|
||||||
namespace AmdGpu {
|
namespace AmdGpu {
|
||||||
@ -20,33 +23,19 @@ namespace Core::Devtools::Widget {
|
|||||||
class FrameDumpViewer;
|
class FrameDumpViewer;
|
||||||
|
|
||||||
class CmdListViewer {
|
class CmdListViewer {
|
||||||
/*
|
|
||||||
* Generic PM4 header
|
|
||||||
*/
|
|
||||||
union PM4Header {
|
|
||||||
struct {
|
|
||||||
u32 reserved : 16;
|
|
||||||
u32 count : 14;
|
|
||||||
u32 type : 2; // PM4_TYPE
|
|
||||||
};
|
|
||||||
u32 u32All;
|
|
||||||
};
|
|
||||||
struct BatchInfo {
|
|
||||||
std::string marker{};
|
|
||||||
size_t start_addr;
|
|
||||||
size_t end_addr;
|
|
||||||
size_t command_addr;
|
|
||||||
AmdGpu::PM4ItOpcode type;
|
|
||||||
bool bypass{false};
|
|
||||||
};
|
|
||||||
|
|
||||||
FrameDumpViewer* parent;
|
uintptr_t base_addr;
|
||||||
std::vector<BatchInfo> batches{};
|
std::string name;
|
||||||
|
std::vector<GPUEvent> events{};
|
||||||
uintptr_t cmdb_addr;
|
uintptr_t cmdb_addr;
|
||||||
size_t cmdb_size;
|
size_t cmdb_size;
|
||||||
|
|
||||||
|
std::string cmdb_view_name;
|
||||||
|
MemoryEditor cmdb_view;
|
||||||
|
|
||||||
int batch_bp{-1};
|
int batch_bp{-1};
|
||||||
int vqid{255};
|
int vqid{255};
|
||||||
|
s32 highlight_batch{-1};
|
||||||
|
|
||||||
void OnNop(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
void OnNop(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||||
void OnSetBase(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
void OnSetBase(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||||
@ -55,7 +44,11 @@ class CmdListViewer {
|
|||||||
void OnDispatch(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
void OnDispatch(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CmdListViewer(FrameDumpViewer* parent, const std::vector<u32>& cmd_list);
|
static void LoadConfig(const char* line);
|
||||||
|
static void SerializeConfig(ImGuiTextBuffer* buf);
|
||||||
|
|
||||||
|
explicit CmdListViewer(const std::vector<u32>& cmd_list, uintptr_t base_addr = 0,
|
||||||
|
std::string name = "");
|
||||||
|
|
||||||
void Draw();
|
void Draw();
|
||||||
};
|
};
|
||||||
|
@ -46,18 +46,18 @@ FrameDumpViewer::FrameDumpViewer(FrameDump _frame_dump) : frame_dump(std::move(_
|
|||||||
|
|
||||||
cmd_list_viewer.reserve(frame_dump.queues.size());
|
cmd_list_viewer.reserve(frame_dump.queues.size());
|
||||||
for (const auto& cmd : frame_dump.queues) {
|
for (const auto& cmd : frame_dump.queues) {
|
||||||
cmd_list_viewer.emplace_back(this, cmd.data);
|
const auto fname =
|
||||||
|
fmt::format("{}_{}_{:02}_{:02}", id, magic_enum::enum_name(selected_queue_type),
|
||||||
|
selected_submit_num, selected_queue_num2);
|
||||||
|
cmd_list_viewer.emplace_back(cmd.data, cmd.base_addr, fname);
|
||||||
if (cmd.type == QueueType::dcb && cmd.submit_num == selected_submit_num &&
|
if (cmd.type == QueueType::dcb && cmd.submit_num == selected_submit_num &&
|
||||||
cmd.num2 == selected_queue_num2) {
|
cmd.num2 == selected_queue_num2) {
|
||||||
selected_cmd = cmd_list_viewer.size() - 1;
|
selected_cmd = cmd_list_viewer.size() - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdb_view.Open = false;
|
|
||||||
cmdb_view.ReadOnly = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameDumpViewer::~FrameDumpViewer() {}
|
FrameDumpViewer::~FrameDumpViewer() = default;
|
||||||
|
|
||||||
void FrameDumpViewer::Draw() {
|
void FrameDumpViewer::Draw() {
|
||||||
if (!is_open) {
|
if (!is_open) {
|
||||||
@ -89,6 +89,24 @@ void FrameDumpViewer::Draw() {
|
|||||||
EndCombo();
|
EndCombo();
|
||||||
}
|
}
|
||||||
SameLine();
|
SameLine();
|
||||||
|
BeginDisabled(selected_cmd == -1);
|
||||||
|
if (SmallButton("Dump cmd")) {
|
||||||
|
auto now_time = fmt::localtime(std::time(nullptr));
|
||||||
|
const auto fname = fmt::format("{:%F %H-%M-%S} {}_{}_{}.bin", now_time,
|
||||||
|
magic_enum::enum_name(selected_queue_type),
|
||||||
|
selected_submit_num, selected_queue_num2);
|
||||||
|
Common::FS::IOFile file(fname, Common::FS::FileAccessMode::Write);
|
||||||
|
auto& data = frame_dump.queues[selected_cmd].data;
|
||||||
|
if (file.IsOpen()) {
|
||||||
|
DebugState.ShowDebugMessage(fmt::format("Dumping cmd as {}", fname));
|
||||||
|
file.Write(data);
|
||||||
|
} else {
|
||||||
|
DebugState.ShowDebugMessage(fmt::format("Failed to save {}", fname));
|
||||||
|
LOG_ERROR(Core, "Failed to open file {}", fname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EndDisabled();
|
||||||
|
|
||||||
TextEx("Submit num");
|
TextEx("Submit num");
|
||||||
SameLine();
|
SameLine();
|
||||||
if (BeginCombo("##select_submit_num", small_int_to_str(selected_submit_num).data(),
|
if (BeginCombo("##select_submit_num", small_int_to_str(selected_submit_num).data(),
|
||||||
@ -144,24 +162,6 @@ void FrameDumpViewer::Draw() {
|
|||||||
}
|
}
|
||||||
EndCombo();
|
EndCombo();
|
||||||
}
|
}
|
||||||
SameLine();
|
|
||||||
BeginDisabled(selected_cmd == -1);
|
|
||||||
if (SmallButton("Dump cmd")) {
|
|
||||||
auto now_time = fmt::localtime(std::time(nullptr));
|
|
||||||
const auto fname = fmt::format("{:%F %H-%M-%S} {}_{}_{}.bin", now_time,
|
|
||||||
magic_enum::enum_name(selected_queue_type),
|
|
||||||
selected_submit_num, selected_queue_num2);
|
|
||||||
Common::FS::IOFile file(fname, Common::FS::FileAccessMode::Write);
|
|
||||||
auto& data = frame_dump.queues[selected_cmd].data;
|
|
||||||
if (file.IsOpen()) {
|
|
||||||
DebugState.ShowDebugMessage(fmt::format("Dumping cmd as {}", fname));
|
|
||||||
file.Write(data);
|
|
||||||
} else {
|
|
||||||
DebugState.ShowDebugMessage(fmt::format("Failed to save {}", fname));
|
|
||||||
LOG_ERROR(Core, "Failed to open file {}", fname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EndDisabled();
|
|
||||||
EndGroup();
|
EndGroup();
|
||||||
|
|
||||||
if (selected_cmd != -1) {
|
if (selected_cmd != -1) {
|
||||||
@ -169,21 +169,6 @@ void FrameDumpViewer::Draw() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
End();
|
End();
|
||||||
|
|
||||||
if (cmdb_view.Open && selected_cmd != -1) {
|
|
||||||
auto& cmd = frame_dump.queues[selected_cmd].data;
|
|
||||||
auto cmd_size = cmd.size() * sizeof(u32);
|
|
||||||
MemoryEditor::Sizes s;
|
|
||||||
cmdb_view.CalcSizes(s, cmd_size, (size_t)cmd.data());
|
|
||||||
SetNextWindowSizeConstraints(ImVec2(0.0f, 0.0f), ImVec2(s.WindowWidth, FLT_MAX));
|
|
||||||
|
|
||||||
char name[64];
|
|
||||||
snprintf(name, sizeof(name), "[GFX] Command buffer %d###cmdbuf_hex_%d", id, id);
|
|
||||||
if (Begin(name, &cmdb_view.Open, ImGuiWindowFlags_NoScrollbar)) {
|
|
||||||
cmdb_view.DrawContents(cmd.data(), cmd_size, (size_t)cmd.data());
|
|
||||||
}
|
|
||||||
End();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Devtools::Widget
|
} // namespace Core::Devtools::Widget
|
||||||
|
@ -21,7 +21,6 @@ class FrameDumpViewer {
|
|||||||
int id;
|
int id;
|
||||||
|
|
||||||
std::vector<CmdListViewer> cmd_list_viewer;
|
std::vector<CmdListViewer> cmd_list_viewer;
|
||||||
MemoryEditor cmdb_view;
|
|
||||||
|
|
||||||
DebugStateType::QueueType selected_queue_type;
|
DebugStateType::QueueType selected_queue_type;
|
||||||
s32 selected_submit_num;
|
s32 selected_submit_num;
|
||||||
|
48
src/core/devtools/widget/types.h
Normal file
48
src/core/devtools/widget/types.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
#include "common/types.h"
|
||||||
|
#include "video_core/amdgpu/pm4_opcodes.h"
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic PM4 header
|
||||||
|
*/
|
||||||
|
union PM4Header {
|
||||||
|
struct {
|
||||||
|
u32 reserved : 16;
|
||||||
|
u32 count : 14;
|
||||||
|
u32 type : 2; // PM4_TYPE
|
||||||
|
};
|
||||||
|
u32 u32All;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PushMarker {
|
||||||
|
std::string name{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PopMarker {};
|
||||||
|
|
||||||
|
struct BatchBegin {
|
||||||
|
u32 id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BatchInfo {
|
||||||
|
u32 id;
|
||||||
|
std::string marker{};
|
||||||
|
size_t start_addr;
|
||||||
|
size_t end_addr;
|
||||||
|
size_t command_addr;
|
||||||
|
AmdGpu::PM4ItOpcode type;
|
||||||
|
bool bypass{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
using GPUEvent = std::variant<PushMarker, PopMarker, BatchBegin, BatchInfo>;
|
||||||
|
|
||||||
|
} // namespace Core::Devtools::Widget
|
@ -519,10 +519,12 @@ void PS4_SYSV_ABI sceGnmDingDong(u32 gnm_vqid, u32 next_offs_dw) {
|
|||||||
// Dumping them using the current ring pointer would result in files containing only the
|
// Dumping them using the current ring pointer would result in files containing only the
|
||||||
// `IndirectBuffer` command. To access the actual command stream, we need to unwrap the IB.
|
// `IndirectBuffer` command. To access the actual command stream, we need to unwrap the IB.
|
||||||
auto acb = acb_span;
|
auto acb = acb_span;
|
||||||
|
auto base_addr = reinterpret_cast<uintptr_t>(acb_ptr);
|
||||||
const auto* indirect_buffer =
|
const auto* indirect_buffer =
|
||||||
reinterpret_cast<const PM4CmdIndirectBuffer*>(acb_span.data());
|
reinterpret_cast<const PM4CmdIndirectBuffer*>(acb_span.data());
|
||||||
if (indirect_buffer->header.opcode == PM4ItOpcode::IndirectBuffer) {
|
if (indirect_buffer->header.opcode == PM4ItOpcode::IndirectBuffer) {
|
||||||
acb = {indirect_buffer->Address<const u32>(), indirect_buffer->ib_size};
|
base_addr = reinterpret_cast<uintptr_t>(indirect_buffer->Address<const u32>());
|
||||||
|
acb = {reinterpret_cast<const u32*>(base_addr), indirect_buffer->ib_size};
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace DebugStateType;
|
using namespace DebugStateType;
|
||||||
@ -532,6 +534,7 @@ void PS4_SYSV_ABI sceGnmDingDong(u32 gnm_vqid, u32 next_offs_dw) {
|
|||||||
.submit_num = seq_num,
|
.submit_num = seq_num,
|
||||||
.num2 = gnm_vqid,
|
.num2 = gnm_vqid,
|
||||||
.data = {acb.begin(), acb.end()},
|
.data = {acb.begin(), acb.end()},
|
||||||
|
.base_addr = base_addr,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1125,9 +1128,25 @@ int PS4_SYSV_ABI sceGnmInsertSetColorMarker() {
|
|||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceGnmInsertSetMarker() {
|
s32 PS4_SYSV_ABI sceGnmInsertSetMarker(u32* cmdbuf, u32 size, const char* marker) {
|
||||||
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
|
LOG_TRACE(Lib_GnmDriver, "called");
|
||||||
return ORBIS_OK;
|
|
||||||
|
if (cmdbuf && marker) {
|
||||||
|
const auto len = std::strlen(marker);
|
||||||
|
const u32 packet_size = ((len + 8) >> 2) + ((len + 0xc) >> 3) * 2;
|
||||||
|
if (packet_size + 2 == size) {
|
||||||
|
auto* nop = reinterpret_cast<PM4CmdNop*>(cmdbuf);
|
||||||
|
nop->header =
|
||||||
|
PM4Type3Header{PM4ItOpcode::Nop, packet_size, PM4ShaderType::ShaderGraphics};
|
||||||
|
nop->data_block[0] = PM4CmdNop::PayloadType::DebugSetMarker;
|
||||||
|
const auto marker_len = len + 1;
|
||||||
|
std::memcpy(&nop->data_block[1], marker, marker_len);
|
||||||
|
std::memset(reinterpret_cast<u8*>(&nop->data_block[1]) + marker_len, 0,
|
||||||
|
packet_size * 4 - marker_len);
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceGnmInsertThreadTraceMarker() {
|
int PS4_SYSV_ABI sceGnmInsertThreadTraceMarker() {
|
||||||
@ -2163,12 +2182,14 @@ s32 PS4_SYSV_ABI sceGnmSubmitCommandBuffers(u32 count, const u32* dcb_gpu_addrs[
|
|||||||
.submit_num = seq_num,
|
.submit_num = seq_num,
|
||||||
.num2 = cbpair,
|
.num2 = cbpair,
|
||||||
.data = {dcb_span.begin(), dcb_span.end()},
|
.data = {dcb_span.begin(), dcb_span.end()},
|
||||||
|
.base_addr = reinterpret_cast<uintptr_t>(dcb_gpu_addrs[cbpair]),
|
||||||
});
|
});
|
||||||
DebugState.PushQueueDump({
|
DebugState.PushQueueDump({
|
||||||
.type = QueueType::ccb,
|
.type = QueueType::ccb,
|
||||||
.submit_num = seq_num,
|
.submit_num = seq_num,
|
||||||
.num2 = cbpair,
|
.num2 = cbpair,
|
||||||
.data = {ccb_span.begin(), ccb_span.end()},
|
.data = {ccb_span.begin(), ccb_span.end()},
|
||||||
|
.base_addr = reinterpret_cast<uintptr_t>(ccb),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ s32 PS4_SYSV_ABI sceGnmInsertPopMarker(u32* cmdbuf, u32 size);
|
|||||||
s32 PS4_SYSV_ABI sceGnmInsertPushColorMarker(u32* cmdbuf, u32 size, const char* marker, u32 color);
|
s32 PS4_SYSV_ABI sceGnmInsertPushColorMarker(u32* cmdbuf, u32 size, const char* marker, u32 color);
|
||||||
s32 PS4_SYSV_ABI sceGnmInsertPushMarker(u32* cmdbuf, u32 size, const char* marker);
|
s32 PS4_SYSV_ABI sceGnmInsertPushMarker(u32* cmdbuf, u32 size, const char* marker);
|
||||||
int PS4_SYSV_ABI sceGnmInsertSetColorMarker();
|
int PS4_SYSV_ABI sceGnmInsertSetColorMarker();
|
||||||
int PS4_SYSV_ABI sceGnmInsertSetMarker();
|
s32 PS4_SYSV_ABI sceGnmInsertSetMarker(u32* cmdbuf, u32 size, const char* marker);
|
||||||
int PS4_SYSV_ABI sceGnmInsertThreadTraceMarker();
|
int PS4_SYSV_ABI sceGnmInsertThreadTraceMarker();
|
||||||
s32 PS4_SYSV_ABI sceGnmInsertWaitFlipDone(u32* cmdbuf, u32 size, s32 vo_handle, u32 buf_idx);
|
s32 PS4_SYSV_ABI sceGnmInsertWaitFlipDone(u32* cmdbuf, u32 size, s32 vo_handle, u32 buf_idx);
|
||||||
int PS4_SYSV_ABI sceGnmIsCoredumpValid();
|
int PS4_SYSV_ABI sceGnmIsCoredumpValid();
|
||||||
|
@ -213,6 +213,7 @@ struct PM4CmdNop {
|
|||||||
enum PayloadType : u32 {
|
enum PayloadType : u32 {
|
||||||
DebugMarkerPush = 0x68750001u, ///< Begin of GPU event scope
|
DebugMarkerPush = 0x68750001u, ///< Begin of GPU event scope
|
||||||
DebugMarkerPop = 0x68750002u, ///< End of GPU event scope
|
DebugMarkerPop = 0x68750002u, ///< End of GPU event scope
|
||||||
|
DebugSetMarker = 0x68750003u, ///< Set GPU event marker
|
||||||
SetVsharpInUdata = 0x68750004u, ///< Indicates that V# will be set in the next packet
|
SetVsharpInUdata = 0x68750004u, ///< Indicates that V# will be set in the next packet
|
||||||
SetTsharpInUdata = 0x68750005u, ///< Indicates that T# will be set in the next packet
|
SetTsharpInUdata = 0x68750005u, ///< Indicates that T# will be set in the next packet
|
||||||
SetSsharpInUdata = 0x68750006u, ///< Indicates that S# will be set in the next packet
|
SetSsharpInUdata = 0x68750006u, ///< Indicates that S# will be set in the next packet
|
||||||
|
Loading…
Reference in New Issue
Block a user