mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-12-11 14:19:10 +00:00
Devtools: PM4 Explorer (#1094)
* Devtools: Pause system * Devtools: pm4 viewer - new menu bar - refactored video_info layer - dump & inspect pm4 packets - removed dumpPM4 config - renamed System to DebugState - add docking space - simple video info constrained to window size * Devtools: pm4 viewer - add combo to select the queue * Devtools: pm4 viewer - add hex editor * Devtools: pm4 viewer - dump current cmd * add monospaced font to devtools * Devtools: pm4 viewer - use spec op name avoid some allocations
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
#include "common/path_util.h"
|
||||
#include "common/slot_vector.h"
|
||||
#include "core/address_space.h"
|
||||
#include "core/debug_state.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/kernel/libkernel.h"
|
||||
#include "core/libraries/libs.h"
|
||||
@@ -320,20 +321,6 @@ static void WaitGpuIdle() {
|
||||
cv_lock.wait(lock, [] { return submission_lock == 0; });
|
||||
}
|
||||
|
||||
static void DumpCommandList(std::span<const u32> cmd_list, const std::string& postfix) {
|
||||
using namespace Common::FS;
|
||||
const auto dump_dir = GetUserPath(PathType::PM4Dir);
|
||||
if (!std::filesystem::exists(dump_dir)) {
|
||||
std::filesystem::create_directories(dump_dir);
|
||||
}
|
||||
if (cmd_list.empty()) {
|
||||
return;
|
||||
}
|
||||
const auto filename = fmt::format("{:08}_{}", frames_submitted, postfix);
|
||||
const auto file = IOFile{dump_dir / filename, FileAccessMode::Write};
|
||||
file.WriteSpan(cmd_list);
|
||||
}
|
||||
|
||||
// Write a special ending NOP packet with N DWs data block
|
||||
template <u32 data_block_size>
|
||||
static inline u32* WriteTrailingNop(u32* cmdbuf) {
|
||||
@@ -507,16 +494,18 @@ void PS4_SYSV_ABI sceGnmDingDong(u32 gnm_vqid, u32 next_offs_dw) {
|
||||
|
||||
WaitGpuIdle();
|
||||
|
||||
/* Suspend logic goes here */
|
||||
if (DebugState.ShouldPauseInSubmit()) {
|
||||
DebugState.PauseGuestThreads();
|
||||
}
|
||||
|
||||
auto vqid = gnm_vqid - 1;
|
||||
auto& asc_queue = asc_queues[{vqid}];
|
||||
const auto* acb_ptr = reinterpret_cast<const u32*>(asc_queue.map_addr + *asc_queue.read_addr);
|
||||
const auto acb_size = next_offs_dw ? (next_offs_dw << 2u) - *asc_queue.read_addr
|
||||
: (asc_queue.ring_size_dw << 2u) - *asc_queue.read_addr;
|
||||
const std::span<const u32> acb_span{acb_ptr, acb_size >> 2u};
|
||||
const std::span acb_span{acb_ptr, acb_size >> 2u};
|
||||
|
||||
if (Config::dumpPM4()) {
|
||||
if (DebugState.DumpingCurrentFrame()) {
|
||||
static auto last_frame_num = -1LL;
|
||||
static u32 seq_num{};
|
||||
if (last_frame_num == frames_submitted) {
|
||||
@@ -536,8 +525,14 @@ void PS4_SYSV_ABI sceGnmDingDong(u32 gnm_vqid, u32 next_offs_dw) {
|
||||
acb = {indirect_buffer->Address<const u32>(), indirect_buffer->ib_size};
|
||||
}
|
||||
|
||||
// File name format is: <queue>_<queue num>_<submit_num>
|
||||
DumpCommandList(acb, fmt::format("acb_{}_{}", gnm_vqid, seq_num));
|
||||
using namespace DebugStateType;
|
||||
|
||||
DebugState.PushQueueDump({
|
||||
.type = QueueType::acb,
|
||||
.submit_num = seq_num,
|
||||
.num2 = gnm_vqid,
|
||||
.data = {acb.begin(), acb.end()},
|
||||
});
|
||||
}
|
||||
|
||||
liverpool->SubmitAsc(vqid, acb_span);
|
||||
@@ -2108,7 +2103,9 @@ s32 PS4_SYSV_ABI sceGnmSubmitCommandBuffers(u32 count, const u32* dcb_gpu_addrs[
|
||||
|
||||
WaitGpuIdle();
|
||||
|
||||
/* Suspend logic goes here */
|
||||
if (DebugState.ShouldPauseInSubmit()) {
|
||||
DebugState.PauseGuestThreads();
|
||||
}
|
||||
|
||||
if (send_init_packet) {
|
||||
if (sdk_version <= 0x1ffffffu) {
|
||||
@@ -2128,10 +2125,10 @@ s32 PS4_SYSV_ABI sceGnmSubmitCommandBuffers(u32 count, const u32* dcb_gpu_addrs[
|
||||
const auto dcb_size_dw = dcb_sizes_in_bytes[cbpair] >> 2;
|
||||
const auto ccb_size_dw = ccb_size_in_bytes >> 2;
|
||||
|
||||
const auto& dcb_span = std::span<const u32>{dcb_gpu_addrs[cbpair], dcb_size_dw};
|
||||
const auto& ccb_span = std::span<const u32>{ccb, ccb_size_dw};
|
||||
const auto& dcb_span = std::span{dcb_gpu_addrs[cbpair], dcb_size_dw};
|
||||
const auto& ccb_span = std::span{ccb, ccb_size_dw};
|
||||
|
||||
if (Config::dumpPM4()) {
|
||||
if (DebugState.DumpingCurrentFrame()) {
|
||||
static auto last_frame_num = -1LL;
|
||||
static u32 seq_num{};
|
||||
if (last_frame_num == frames_submitted && cbpair == 0) {
|
||||
@@ -2141,9 +2138,20 @@ s32 PS4_SYSV_ABI sceGnmSubmitCommandBuffers(u32 count, const u32* dcb_gpu_addrs[
|
||||
seq_num = 0u;
|
||||
}
|
||||
|
||||
// File name format is: <queue>_<submit num>_<buffer_in_submit>
|
||||
DumpCommandList(dcb_span, fmt::format("dcb_{}_{}", seq_num, cbpair));
|
||||
DumpCommandList(ccb_span, fmt::format("ccb_{}_{}", seq_num, cbpair));
|
||||
using DebugStateType::QueueType;
|
||||
|
||||
DebugState.PushQueueDump({
|
||||
.type = QueueType::dcb,
|
||||
.submit_num = seq_num,
|
||||
.num2 = cbpair,
|
||||
.data = {dcb_span.begin(), dcb_span.end()},
|
||||
});
|
||||
DebugState.PushQueueDump({
|
||||
.type = QueueType::ccb,
|
||||
.submit_num = seq_num,
|
||||
.num2 = cbpair,
|
||||
.data = {ccb_span.begin(), ccb_span.end()},
|
||||
});
|
||||
}
|
||||
|
||||
liverpool->SubmitGfx(dcb_span, ccb_span);
|
||||
@@ -2166,6 +2174,7 @@ int PS4_SYSV_ABI sceGnmSubmitDone() {
|
||||
liverpool->SubmitDone();
|
||||
send_init_packet = true;
|
||||
++frames_submitted;
|
||||
DebugState.IncGnmFrameNum();
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "common/singleton.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/debug_state.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/kernel/libkernel.h"
|
||||
#include "core/libraries/kernel/thread_management.h"
|
||||
@@ -988,6 +989,7 @@ static void cleanup_thread(void* arg) {
|
||||
}
|
||||
Core::SetTcbBase(nullptr);
|
||||
thread->is_almost_done = true;
|
||||
DebugState.RemoveCurrentThreadFromGuestList();
|
||||
}
|
||||
|
||||
static void* run_thread(void* arg) {
|
||||
@@ -998,6 +1000,7 @@ static void* run_thread(void* arg) {
|
||||
g_pthread_self = thread;
|
||||
pthread_cleanup_push(cleanup_thread, thread);
|
||||
thread->is_started = true;
|
||||
DebugState.AddCurrentThreadToGuestList();
|
||||
ret = linker->ExecuteGuest(thread->entry, thread->arg);
|
||||
pthread_cleanup_pop(1);
|
||||
return ret;
|
||||
|
||||
@@ -247,6 +247,17 @@ int PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2,
|
||||
return SCE_OK;
|
||||
}
|
||||
|
||||
namespace Dev {
|
||||
u64& GetInitialPtc() {
|
||||
return initial_ptc;
|
||||
}
|
||||
|
||||
Common::NativeClock* GetClock() {
|
||||
return clock.get();
|
||||
}
|
||||
|
||||
} // namespace Dev
|
||||
|
||||
void timeSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
||||
clock = std::make_unique<Common::NativeClock>();
|
||||
initial_ptc = clock->GetUptime();
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Common {
|
||||
class NativeClock;
|
||||
}
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
@@ -47,6 +51,12 @@ constexpr int ORBIS_CLOCK_EXT_DEBUG_NETWORK = 17;
|
||||
constexpr int ORBIS_CLOCK_EXT_AD_NETWORK = 18;
|
||||
constexpr int ORBIS_CLOCK_EXT_RAW_NETWORK = 19;
|
||||
|
||||
namespace Dev {
|
||||
u64& GetInitialPtc();
|
||||
|
||||
Common::NativeClock* GetClock();
|
||||
} // namespace Dev
|
||||
|
||||
u64 PS4_SYSV_ABI sceKernelGetTscFrequency();
|
||||
u64 PS4_SYSV_ABI sceKernelGetProcessTime();
|
||||
u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounter();
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <imgui.h>
|
||||
#include "common/assert.h"
|
||||
@@ -281,10 +282,15 @@ void MsgDialogUi::Draw() {
|
||||
first_render = false;
|
||||
}
|
||||
|
||||
DialogResult Libraries::MsgDialog::ShowMsgDialog(MsgDialogState state, bool block) {
|
||||
DialogResult result{};
|
||||
Status status = Status::RUNNING;
|
||||
MsgDialogUi dialog(&state, &status, &result);
|
||||
DialogResult Libraries::MsgDialog::ShowMsgDialog(MsgDialogState p_state, bool block) {
|
||||
static DialogResult result{};
|
||||
static Status status;
|
||||
static MsgDialogUi dialog;
|
||||
static MsgDialogState state;
|
||||
dialog = MsgDialogUi{};
|
||||
status = Status::RUNNING;
|
||||
state = std::move(p_state);
|
||||
dialog = MsgDialogUi(&state, &status, &result);
|
||||
if (block) {
|
||||
while (status == Status::RUNNING) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "common/config.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/debug_state.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/kernel/time_management.h"
|
||||
#include "core/libraries/videoout/driver.h"
|
||||
@@ -284,7 +285,7 @@ void VideoOutDriver::PresentThread(std::stop_token token) {
|
||||
if (vblank_status.count % (main_port.flip_rate + 1) == 0) {
|
||||
const auto request = receive_request();
|
||||
if (!request) {
|
||||
if (!main_port.is_open) {
|
||||
if (!main_port.is_open || DebugState.IsGuestThreadsPaused()) {
|
||||
DrawBlankFrame();
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user