mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-03 14:48:46 +00:00
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
This commit is contained in:
parent
983cafb5f2
commit
96a0201417
39 changed files with 17883 additions and 399 deletions
|
@ -338,6 +338,18 @@ set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
|
||||||
src/core/libraries/screenshot/screenshot.h
|
src/core/libraries/screenshot/screenshot.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(DEV_TOOLS src/core/devtools/layer.cpp
|
||||||
|
src/core/devtools/layer.h
|
||||||
|
src/core/devtools/gcn/gcn_context_regs.cpp
|
||||||
|
src/core/devtools/gcn/gcn_shader_regs.cpp
|
||||||
|
src/core/devtools/widget/cmd_list.cpp
|
||||||
|
src/core/devtools/widget/cmd_list.h
|
||||||
|
src/core/devtools/widget/frame_dump.cpp
|
||||||
|
src/core/devtools/widget/frame_dump.h
|
||||||
|
src/core/devtools/widget/frame_graph.cpp
|
||||||
|
src/core/devtools/widget/frame_graph.h
|
||||||
|
)
|
||||||
|
|
||||||
set(COMMON src/common/logging/backend.cpp
|
set(COMMON src/common/logging/backend.cpp
|
||||||
src/common/logging/backend.h
|
src/common/logging/backend.h
|
||||||
src/common/logging/filter.cpp
|
src/common/logging/filter.cpp
|
||||||
|
@ -449,6 +461,9 @@ set(CORE src/core/aerolib/stubs.cpp
|
||||||
${USBD_LIB}
|
${USBD_LIB}
|
||||||
${MISC_LIBS}
|
${MISC_LIBS}
|
||||||
${DIALOGS_LIB}
|
${DIALOGS_LIB}
|
||||||
|
${DEV_TOOLS}
|
||||||
|
src/core/debug_state.cpp
|
||||||
|
src/core/debug_state.h
|
||||||
src/core/linker.cpp
|
src/core/linker.cpp
|
||||||
src/core/linker.h
|
src/core/linker.h
|
||||||
src/core/memory.cpp
|
src/core/memory.cpp
|
||||||
|
@ -458,8 +473,6 @@ set(CORE src/core/aerolib/stubs.cpp
|
||||||
src/core/platform.h
|
src/core/platform.h
|
||||||
src/core/signals.cpp
|
src/core/signals.cpp
|
||||||
src/core/signals.h
|
src/core/signals.h
|
||||||
src/core/system.cpp
|
|
||||||
src/core/system.h
|
|
||||||
src/core/tls.cpp
|
src/core/tls.cpp
|
||||||
src/core/tls.h
|
src/core/tls.h
|
||||||
src/core/virtual_memory.cpp
|
src/core/virtual_memory.cpp
|
||||||
|
@ -625,8 +638,6 @@ set(IMGUI src/imgui/imgui_config.h
|
||||||
src/imgui/imgui_layer.h
|
src/imgui/imgui_layer.h
|
||||||
src/imgui/imgui_std.h
|
src/imgui/imgui_std.h
|
||||||
src/imgui/imgui_texture.h
|
src/imgui/imgui_texture.h
|
||||||
src/imgui/layer/video_info.cpp
|
|
||||||
src/imgui/layer/video_info.h
|
|
||||||
src/imgui/renderer/imgui_core.cpp
|
src/imgui/renderer/imgui_core.cpp
|
||||||
src/imgui/renderer/imgui_core.h
|
src/imgui/renderer/imgui_core.h
|
||||||
src/imgui/renderer/imgui_impl_sdl3.cpp
|
src/imgui/renderer/imgui_impl_sdl3.cpp
|
||||||
|
@ -725,7 +736,7 @@ endif()
|
||||||
|
|
||||||
create_target_directory_groups(shadps4)
|
create_target_directory_groups(shadps4)
|
||||||
|
|
||||||
target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui)
|
target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn)
|
||||||
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::SPIRV glslang::glslang SDL3::SDL3 pugixml::pugixml)
|
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::SPIRV glslang::glslang SDL3::SDL3 pugixml::pugixml)
|
||||||
|
|
||||||
target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
|
target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
|
||||||
|
|
|
@ -73,3 +73,9 @@ path = "src/imgui/renderer/fonts/NotoSansJP-Regular.ttf"
|
||||||
precedence = "aggregate"
|
precedence = "aggregate"
|
||||||
SPDX-FileCopyrightText = "2012 Google Inc. All Rights Reserved."
|
SPDX-FileCopyrightText = "2012 Google Inc. All Rights Reserved."
|
||||||
SPDX-License-Identifier = "OFL-1.1"
|
SPDX-License-Identifier = "OFL-1.1"
|
||||||
|
|
||||||
|
[[annotations]]
|
||||||
|
path = "externals/gcn/include/**"
|
||||||
|
SPDX-FileCopyrightText = "NONE"
|
||||||
|
SPDX-License-Identifier = "CC0-1.0"
|
||||||
|
|
||||||
|
|
3
externals/CMakeLists.txt
vendored
3
externals/CMakeLists.txt
vendored
|
@ -183,3 +183,6 @@ add_subdirectory(tracy)
|
||||||
if (NOT TARGET pugixml::pugixml)
|
if (NOT TARGET pugixml::pugixml)
|
||||||
add_subdirectory(pugixml)
|
add_subdirectory(pugixml)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# GCN Headers
|
||||||
|
add_subdirectory(gcn)
|
8
externals/gcn/CMakeLists.txt
vendored
Normal file
8
externals/gcn/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
project(gcn LANGUAGES CXX)
|
||||||
|
|
||||||
|
add_library(gcn dummy.cpp)
|
||||||
|
|
||||||
|
target_include_directories(gcn INTERFACE include)
|
2
externals/gcn/dummy.cpp
vendored
Normal file
2
externals/gcn/dummy.cpp
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
15339
externals/gcn/include/gcn/si_ci_vi_merged_offset.h
vendored
Normal file
15339
externals/gcn/include/gcn/si_ci_vi_merged_offset.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
@ -49,7 +49,6 @@ static bool isAutoUpdate = false;
|
||||||
static bool isNullGpu = false;
|
static bool isNullGpu = false;
|
||||||
static bool shouldCopyGPUBuffers = false;
|
static bool shouldCopyGPUBuffers = false;
|
||||||
static bool shouldDumpShaders = false;
|
static bool shouldDumpShaders = false;
|
||||||
static bool shouldDumpPM4 = false;
|
|
||||||
static u32 vblankDivider = 1;
|
static u32 vblankDivider = 1;
|
||||||
static bool vkValidation = false;
|
static bool vkValidation = false;
|
||||||
static bool vkValidationSync = false;
|
static bool vkValidationSync = false;
|
||||||
|
@ -156,10 +155,6 @@ bool dumpShaders() {
|
||||||
return shouldDumpShaders;
|
return shouldDumpShaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool dumpPM4() {
|
|
||||||
return shouldDumpPM4;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isRdocEnabled() {
|
bool isRdocEnabled() {
|
||||||
return rdocEnable;
|
return rdocEnable;
|
||||||
}
|
}
|
||||||
|
@ -228,10 +223,6 @@ void setDumpShaders(bool enable) {
|
||||||
shouldDumpShaders = enable;
|
shouldDumpShaders = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDumpPM4(bool enable) {
|
|
||||||
shouldDumpPM4 = enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setVkValidation(bool enable) {
|
void setVkValidation(bool enable) {
|
||||||
vkValidation = enable;
|
vkValidation = enable;
|
||||||
}
|
}
|
||||||
|
@ -461,7 +452,6 @@ void load(const std::filesystem::path& path) {
|
||||||
isNullGpu = toml::find_or<bool>(gpu, "nullGpu", false);
|
isNullGpu = toml::find_or<bool>(gpu, "nullGpu", false);
|
||||||
shouldCopyGPUBuffers = toml::find_or<bool>(gpu, "copyGPUBuffers", false);
|
shouldCopyGPUBuffers = toml::find_or<bool>(gpu, "copyGPUBuffers", false);
|
||||||
shouldDumpShaders = toml::find_or<bool>(gpu, "dumpShaders", false);
|
shouldDumpShaders = toml::find_or<bool>(gpu, "dumpShaders", false);
|
||||||
shouldDumpPM4 = toml::find_or<bool>(gpu, "dumpPM4", false);
|
|
||||||
vblankDivider = toml::find_or<int>(gpu, "vblankDivider", 1);
|
vblankDivider = toml::find_or<int>(gpu, "vblankDivider", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,7 +540,6 @@ void save(const std::filesystem::path& path) {
|
||||||
data["GPU"]["nullGpu"] = isNullGpu;
|
data["GPU"]["nullGpu"] = isNullGpu;
|
||||||
data["GPU"]["copyGPUBuffers"] = shouldCopyGPUBuffers;
|
data["GPU"]["copyGPUBuffers"] = shouldCopyGPUBuffers;
|
||||||
data["GPU"]["dumpShaders"] = shouldDumpShaders;
|
data["GPU"]["dumpShaders"] = shouldDumpShaders;
|
||||||
data["GPU"]["dumpPM4"] = shouldDumpPM4;
|
|
||||||
data["GPU"]["vblankDivider"] = vblankDivider;
|
data["GPU"]["vblankDivider"] = vblankDivider;
|
||||||
data["Vulkan"]["gpuId"] = gpuId;
|
data["Vulkan"]["gpuId"] = gpuId;
|
||||||
data["Vulkan"]["validation"] = vkValidation;
|
data["Vulkan"]["validation"] = vkValidation;
|
||||||
|
@ -609,7 +598,6 @@ void setDefaultValues() {
|
||||||
isAutoUpdate = false;
|
isAutoUpdate = false;
|
||||||
isNullGpu = false;
|
isNullGpu = false;
|
||||||
shouldDumpShaders = false;
|
shouldDumpShaders = false;
|
||||||
shouldDumpPM4 = false;
|
|
||||||
vblankDivider = 1;
|
vblankDivider = 1;
|
||||||
vkValidation = false;
|
vkValidation = false;
|
||||||
vkValidationSync = false;
|
vkValidationSync = false;
|
||||||
|
|
|
@ -34,7 +34,6 @@ bool autoUpdate();
|
||||||
bool nullGpu();
|
bool nullGpu();
|
||||||
bool copyGPUCmdBuffers();
|
bool copyGPUCmdBuffers();
|
||||||
bool dumpShaders();
|
bool dumpShaders();
|
||||||
bool dumpPM4();
|
|
||||||
bool isRdocEnabled();
|
bool isRdocEnabled();
|
||||||
u32 vblankDiv();
|
u32 vblankDiv();
|
||||||
|
|
||||||
|
@ -44,7 +43,6 @@ void setAutoUpdate(bool enable);
|
||||||
void setNullGpu(bool enable);
|
void setNullGpu(bool enable);
|
||||||
void setCopyGPUCmdBuffers(bool enable);
|
void setCopyGPUCmdBuffers(bool enable);
|
||||||
void setDumpShaders(bool enable);
|
void setDumpShaders(bool enable);
|
||||||
void setDumpPM4(bool enable);
|
|
||||||
void setVblankDiv(u32 value);
|
void setVblankDiv(u32 value);
|
||||||
void setGpuId(s32 selectedGpuId);
|
void setGpuId(s32 selectedGpuId);
|
||||||
void setScreenWidth(u32 width);
|
void setScreenWidth(u32 width);
|
||||||
|
|
|
@ -110,7 +110,6 @@ static auto UserPaths = [] {
|
||||||
create_path(PathType::LogDir, user_dir / LOG_DIR);
|
create_path(PathType::LogDir, user_dir / LOG_DIR);
|
||||||
create_path(PathType::ScreenshotsDir, user_dir / SCREENSHOTS_DIR);
|
create_path(PathType::ScreenshotsDir, user_dir / SCREENSHOTS_DIR);
|
||||||
create_path(PathType::ShaderDir, user_dir / SHADER_DIR);
|
create_path(PathType::ShaderDir, user_dir / SHADER_DIR);
|
||||||
create_path(PathType::PM4Dir, user_dir / PM4_DIR);
|
|
||||||
create_path(PathType::SaveDataDir, user_dir / SAVEDATA_DIR);
|
create_path(PathType::SaveDataDir, user_dir / SAVEDATA_DIR);
|
||||||
create_path(PathType::GameDataDir, user_dir / GAMEDATA_DIR);
|
create_path(PathType::GameDataDir, user_dir / GAMEDATA_DIR);
|
||||||
create_path(PathType::TempDataDir, user_dir / TEMPDATA_DIR);
|
create_path(PathType::TempDataDir, user_dir / TEMPDATA_DIR);
|
||||||
|
|
|
@ -17,7 +17,6 @@ enum class PathType {
|
||||||
LogDir, // Where log files are stored.
|
LogDir, // Where log files are stored.
|
||||||
ScreenshotsDir, // Where screenshots are stored.
|
ScreenshotsDir, // Where screenshots are stored.
|
||||||
ShaderDir, // Where shaders are stored.
|
ShaderDir, // Where shaders are stored.
|
||||||
PM4Dir, // Where command lists are stored.
|
|
||||||
SaveDataDir, // Where guest save data is stored.
|
SaveDataDir, // Where guest save data is stored.
|
||||||
TempDataDir, // Where game temp data is stored.
|
TempDataDir, // Where game temp data is stored.
|
||||||
GameDataDir, // Where game data is stored.
|
GameDataDir, // Where game data is stored.
|
||||||
|
@ -35,7 +34,6 @@ constexpr auto PORTABLE_DIR = "user";
|
||||||
constexpr auto LOG_DIR = "log";
|
constexpr auto LOG_DIR = "log";
|
||||||
constexpr auto SCREENSHOTS_DIR = "screenshots";
|
constexpr auto SCREENSHOTS_DIR = "screenshots";
|
||||||
constexpr auto SHADER_DIR = "shader";
|
constexpr auto SHADER_DIR = "shader";
|
||||||
constexpr auto PM4_DIR = "pm4";
|
|
||||||
constexpr auto SAVEDATA_DIR = "savedata";
|
constexpr auto SAVEDATA_DIR = "savedata";
|
||||||
constexpr auto GAMEDATA_DIR = "data";
|
constexpr auto GAMEDATA_DIR = "data";
|
||||||
constexpr auto TEMPDATA_DIR = "temp";
|
constexpr auto TEMPDATA_DIR = "temp";
|
||||||
|
|
102
src/core/debug_state.cpp
Normal file
102
src/core/debug_state.cpp
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "common/native_clock.h"
|
||||||
|
#include "common/singleton.h"
|
||||||
|
#include "debug_state.h"
|
||||||
|
#include "libraries/kernel/event_queues.h"
|
||||||
|
#include "libraries/kernel/time_management.h"
|
||||||
|
#include "libraries/system/msgdialog.h"
|
||||||
|
|
||||||
|
using namespace DebugStateType;
|
||||||
|
|
||||||
|
DebugStateImpl& DebugState = *Common::Singleton<DebugStateImpl>::Instance();
|
||||||
|
|
||||||
|
static ThreadID ThisThreadID() {
|
||||||
|
#ifdef _WIN32
|
||||||
|
return GetCurrentThreadId();
|
||||||
|
#else
|
||||||
|
return pthread_self();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PauseThread(ThreadID id) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
auto handle = OpenThread(THREAD_SUSPEND_RESUME, FALSE, id);
|
||||||
|
SuspendThread(handle);
|
||||||
|
CloseHandle(handle);
|
||||||
|
#else
|
||||||
|
pthread_kill(id, SIGUSR1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ResumeThread(ThreadID id) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
auto handle = OpenThread(THREAD_SUSPEND_RESUME, FALSE, id);
|
||||||
|
ResumeThread(handle);
|
||||||
|
CloseHandle(handle);
|
||||||
|
#else
|
||||||
|
pthread_kill(id, SIGUSR1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugStateImpl::AddCurrentThreadToGuestList() {
|
||||||
|
std::lock_guard lock{guest_threads_mutex};
|
||||||
|
const ThreadID id = ThisThreadID();
|
||||||
|
guest_threads.push_back(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugStateImpl::RemoveCurrentThreadFromGuestList() {
|
||||||
|
std::lock_guard lock{guest_threads_mutex};
|
||||||
|
const ThreadID id = ThisThreadID();
|
||||||
|
std::erase_if(guest_threads, [&](const ThreadID& v) { return v == id; });
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugStateImpl::PauseGuestThreads() {
|
||||||
|
using namespace Libraries::MsgDialog;
|
||||||
|
std::unique_lock lock{guest_threads_mutex};
|
||||||
|
if (is_guest_threads_paused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ShouldPauseInSubmit()) {
|
||||||
|
waiting_submit_pause = false;
|
||||||
|
should_show_frame_dump = true;
|
||||||
|
}
|
||||||
|
bool self_guest = false;
|
||||||
|
ThreadID self_id = ThisThreadID();
|
||||||
|
for (const auto& id : guest_threads) {
|
||||||
|
if (id == self_id) {
|
||||||
|
self_guest = true;
|
||||||
|
} else {
|
||||||
|
PauseThread(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pause_time = Libraries::Kernel::Dev::GetClock()->GetUptime();
|
||||||
|
is_guest_threads_paused = true;
|
||||||
|
lock.unlock();
|
||||||
|
if (self_guest) {
|
||||||
|
PauseThread(self_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugStateImpl::ResumeGuestThreads() {
|
||||||
|
std::lock_guard lock{guest_threads_mutex};
|
||||||
|
if (!is_guest_threads_paused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 delta_time = Libraries::Kernel::Dev::GetClock()->GetUptime() - pause_time;
|
||||||
|
Libraries::Kernel::Dev::GetInitialPtc() += delta_time;
|
||||||
|
for (const auto& id : guest_threads) {
|
||||||
|
ResumeThread(id);
|
||||||
|
}
|
||||||
|
is_guest_threads_paused = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DebugStateImpl::RequestFrameDump(s32 count) {
|
||||||
|
gnm_frame_dump_request_count = count;
|
||||||
|
frame_dump_list.clear();
|
||||||
|
frame_dump_list.resize(count);
|
||||||
|
waiting_submit_pause = true;
|
||||||
|
}
|
116
src/core/debug_state.h
Normal file
116
src/core/debug_state.h
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN 1
|
||||||
|
#endif
|
||||||
|
#include <Windows.h>
|
||||||
|
using ThreadID = DWORD;
|
||||||
|
#else
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <signal.h>
|
||||||
|
using ThreadID = pthread_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Core::Devtools {
|
||||||
|
class Layer;
|
||||||
|
namespace Widget {
|
||||||
|
class FrameGraph;
|
||||||
|
}
|
||||||
|
} // namespace Core::Devtools
|
||||||
|
|
||||||
|
namespace DebugStateType {
|
||||||
|
|
||||||
|
enum class QueueType {
|
||||||
|
acb,
|
||||||
|
dcb,
|
||||||
|
ccb,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct QueueDump {
|
||||||
|
QueueType type;
|
||||||
|
u32 submit_num;
|
||||||
|
u32 num2; // acb: queue_num; else: buffer_in_submit
|
||||||
|
std::vector<u32> data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FrameDump {
|
||||||
|
std::vector<QueueDump> queues;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DebugStateImpl {
|
||||||
|
friend class Core::Devtools::Layer;
|
||||||
|
friend class Core::Devtools::Widget::FrameGraph;
|
||||||
|
|
||||||
|
std::mutex guest_threads_mutex{};
|
||||||
|
std::vector<ThreadID> guest_threads{};
|
||||||
|
std::atomic_bool is_guest_threads_paused = false;
|
||||||
|
u64 pause_time{};
|
||||||
|
|
||||||
|
std::atomic_int32_t flip_frame_count = 0;
|
||||||
|
std::atomic_int32_t gnm_frame_count = 0;
|
||||||
|
|
||||||
|
s32 gnm_frame_dump_request_count = -1;
|
||||||
|
bool waiting_submit_pause = false;
|
||||||
|
bool should_show_frame_dump = false;
|
||||||
|
|
||||||
|
std::mutex frame_dump_list_mutex;
|
||||||
|
std::vector<FrameDump> frame_dump_list{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
void AddCurrentThreadToGuestList();
|
||||||
|
|
||||||
|
void RemoveCurrentThreadFromGuestList();
|
||||||
|
|
||||||
|
void PauseGuestThreads();
|
||||||
|
|
||||||
|
void ResumeGuestThreads();
|
||||||
|
|
||||||
|
bool IsGuestThreadsPaused() const {
|
||||||
|
return is_guest_threads_paused;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IncFlipFrameNum() {
|
||||||
|
++flip_frame_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IncGnmFrameNum() {
|
||||||
|
++gnm_frame_count;
|
||||||
|
--gnm_frame_dump_request_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 GetFrameNum() const {
|
||||||
|
return flip_frame_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DumpingCurrentFrame() const {
|
||||||
|
return gnm_frame_dump_request_count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShouldPauseInSubmit() const {
|
||||||
|
return waiting_submit_pause && gnm_frame_dump_request_count == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RequestFrameDump(s32 count = 1);
|
||||||
|
|
||||||
|
FrameDump& GetFrameDump() {
|
||||||
|
return frame_dump_list[frame_dump_list.size() - gnm_frame_dump_request_count];
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushQueueDump(QueueDump dump) {
|
||||||
|
std::unique_lock lock{frame_dump_list_mutex};
|
||||||
|
GetFrameDump().queues.push_back(std::move(dump));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace DebugStateType
|
||||||
|
|
||||||
|
extern DebugStateType::DebugStateImpl& DebugState;
|
295
src/core/devtools/gcn/gcn_context_regs.cpp
Normal file
295
src/core/devtools/gcn/gcn_context_regs.cpp
Normal file
|
@ -0,0 +1,295 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "common/types.h"
|
||||||
|
#include "gcn/si_ci_vi_merged_offset.h"
|
||||||
|
|
||||||
|
using namespace Pal::Gfx6;
|
||||||
|
|
||||||
|
namespace Core::Devtools::Gcn {
|
||||||
|
const char* GetContextRegName(u32 reg_offset) {
|
||||||
|
switch (reg_offset) {
|
||||||
|
case mmDB_SHADER_CONTROL:
|
||||||
|
return "mmDB_SHADER_CONTROL";
|
||||||
|
case mmCB_SHADER_MASK:
|
||||||
|
return "mmCB_SHADER_MASK";
|
||||||
|
case mmPA_CL_CLIP_CNTL:
|
||||||
|
return "mmPA_CL_CLIP_CNTL";
|
||||||
|
case mmVGT_INSTANCE_STEP_RATE_0:
|
||||||
|
return "mmVGT_INSTANCE_STEP_RATE_0";
|
||||||
|
case mmVGT_INSTANCE_STEP_RATE_1:
|
||||||
|
return "mmVGT_INSTANCE_STEP_RATE_1";
|
||||||
|
case mmVGT_INDX_OFFSET:
|
||||||
|
return "mmVGT_INDX_OFFSET";
|
||||||
|
case mmVGT_SHADER_STAGES_EN:
|
||||||
|
return "mmVGT_SHADER_STAGES_EN";
|
||||||
|
case mmVGT_GS_MODE:
|
||||||
|
return "mmVGT_GS_MODE";
|
||||||
|
case mmVGT_STRMOUT_CONFIG:
|
||||||
|
return "mmVGT_STRMOUT_CONFIG";
|
||||||
|
case mmVGT_OUT_DEALLOC_CNTL:
|
||||||
|
return "mmVGT_OUT_DEALLOC_CNTL";
|
||||||
|
case mmVGT_VTX_CNT_EN:
|
||||||
|
return "mmVGT_VTX_CNT_EN";
|
||||||
|
case mmVGT_MAX_VTX_INDX:
|
||||||
|
return "mmVGT_MAX_VTX_INDX";
|
||||||
|
case mmVGT_MULTI_PRIM_IB_RESET_INDX:
|
||||||
|
return "mmVGT_MULTI_PRIM_IB_RESET_INDX";
|
||||||
|
case mmVGT_OUTPUT_PATH_CNTL:
|
||||||
|
return "mmVGT_OUTPUT_PATH_CNTL";
|
||||||
|
case mmVGT_GS_PER_ES:
|
||||||
|
return "mmVGT_GS_PER_ES";
|
||||||
|
case mmVGT_ES_PER_GS:
|
||||||
|
return "mmVGT_ES_PER_GS";
|
||||||
|
case mmVGT_GS_PER_VS:
|
||||||
|
return "mmVGT_GS_PER_VS";
|
||||||
|
case mmCB_COLOR0_BASE:
|
||||||
|
return "mmCB_COLOR0_BASE";
|
||||||
|
case mmCB_COLOR0_INFO:
|
||||||
|
return "mmCB_COLOR0_INFO";
|
||||||
|
case mmCB_COLOR0_CMASK_SLICE:
|
||||||
|
return "mmCB_COLOR0_CMASK_SLICE";
|
||||||
|
case mmCB_COLOR0_CLEAR_WORD0:
|
||||||
|
return "mmCB_COLOR0_CLEAR_WORD0";
|
||||||
|
case mmCB_COLOR0_CLEAR_WORD1:
|
||||||
|
return "mmCB_COLOR0_CLEAR_WORD1";
|
||||||
|
case mmCB_COLOR0_PITCH:
|
||||||
|
return "mmCB_COLOR0_PITCH";
|
||||||
|
case mmCB_COLOR0_SLICE:
|
||||||
|
return "mmCB_COLOR0_SLICE";
|
||||||
|
case mmCB_COLOR0_VIEW:
|
||||||
|
return "mmCB_COLOR0_VIEW";
|
||||||
|
case mmCB_COLOR0_DCC_CONTROL__VI:
|
||||||
|
return "mmCB_COLOR0_DCC_CONTROL";
|
||||||
|
case mmCB_COLOR0_CMASK:
|
||||||
|
return "mmCB_COLOR0_CMASK";
|
||||||
|
case mmCB_COLOR0_FMASK_SLICE:
|
||||||
|
return "mmCB_COLOR0_FMASK_SLICE";
|
||||||
|
case mmCB_COLOR0_FMASK:
|
||||||
|
return "mmCB_COLOR0_FMASK";
|
||||||
|
case mmCB_COLOR0_DCC_BASE__VI:
|
||||||
|
return "mmCB_COLOR0_DCC_BASE";
|
||||||
|
case mmCB_COLOR0_ATTRIB:
|
||||||
|
return "mmCB_COLOR0_ATTRIB";
|
||||||
|
case mmCB_COLOR1_BASE:
|
||||||
|
return "mmCB_COLOR1_BASE";
|
||||||
|
case mmCB_COLOR1_INFO:
|
||||||
|
return "mmCB_COLOR1_INFO";
|
||||||
|
case mmCB_COLOR1_ATTRIB:
|
||||||
|
return "mmCB_COLOR1_ATTRIB";
|
||||||
|
case mmCB_COLOR1_CMASK_SLICE:
|
||||||
|
return "mmCB_COLOR1_CMASK_SLICE";
|
||||||
|
case mmCB_COLOR1_CLEAR_WORD0:
|
||||||
|
return "mmCB_COLOR1_CLEAR_WORD0";
|
||||||
|
case mmCB_COLOR1_CLEAR_WORD1:
|
||||||
|
return "mmCB_COLOR1_CLEAR_WORD1";
|
||||||
|
case mmCB_COLOR1_PITCH:
|
||||||
|
return "mmCB_COLOR1_PITCH";
|
||||||
|
case mmCB_COLOR1_VIEW:
|
||||||
|
return "mmCB_COLOR1_VIEW";
|
||||||
|
case mmCB_COLOR2_INFO:
|
||||||
|
return "mmCB_COLOR2_INFO";
|
||||||
|
case mmCB_COLOR2_ATTRIB:
|
||||||
|
return "mmCB_COLOR2_ATTRIB";
|
||||||
|
case mmCB_COLOR2_CMASK_SLICE:
|
||||||
|
return "mmCB_COLOR2_CMASK_SLICE";
|
||||||
|
case mmCB_COLOR2_CLEAR_WORD0:
|
||||||
|
return "mmCB_COLOR2_CLEAR_WORD0";
|
||||||
|
case mmCB_COLOR2_CLEAR_WORD1:
|
||||||
|
return "mmCB_COLOR2_CLEAR_WORD1";
|
||||||
|
case mmCB_COLOR2_PITCH:
|
||||||
|
return "mmCB_COLOR2_PITCH";
|
||||||
|
case mmCB_COLOR2_VIEW:
|
||||||
|
return "mmCB_COLOR2_VIEW";
|
||||||
|
case mmCB_COLOR3_INFO:
|
||||||
|
return "mmCB_COLOR3_INFO";
|
||||||
|
case mmCB_COLOR3_CMASK_SLICE:
|
||||||
|
return "mmCB_COLOR3_CMASK_SLICE";
|
||||||
|
case mmCB_COLOR4_INFO:
|
||||||
|
return "mmCB_COLOR4_INFO";
|
||||||
|
case mmCB_COLOR5_INFO:
|
||||||
|
return "mmCB_COLOR5_INFO";
|
||||||
|
case mmCB_COLOR6_INFO:
|
||||||
|
return "mmCB_COLOR6_INFO";
|
||||||
|
case mmCB_COLOR7_INFO:
|
||||||
|
return "mmCB_COLOR7_INFO";
|
||||||
|
case mmDB_SRESULTS_COMPARE_STATE0:
|
||||||
|
return "mmDB_SRESULTS_COMPARE_STATE0";
|
||||||
|
case mmDB_SRESULTS_COMPARE_STATE1:
|
||||||
|
return "mmDB_SRESULTS_COMPARE_STATE1";
|
||||||
|
case mmDB_DEPTH_CONTROL:
|
||||||
|
return "mmDB_DEPTH_CONTROL";
|
||||||
|
case mmDB_EQAA:
|
||||||
|
return "mmDB_EQAA";
|
||||||
|
case mmPA_SU_POINT_SIZE:
|
||||||
|
return "mmPA_SU_POINT_SIZE";
|
||||||
|
case mmPA_SU_POINT_MINMAX:
|
||||||
|
return "mmPA_SU_POINT_MINMAX";
|
||||||
|
case mmPA_SU_SC_MODE_CNTL:
|
||||||
|
return "mmPA_SU_SC_MODE_CNTL";
|
||||||
|
case mmPA_SU_POLY_OFFSET_DB_FMT_CNTL:
|
||||||
|
return "mmPA_SU_POLY_OFFSET_DB_FMT_CNTL";
|
||||||
|
case mmPA_SC_CLIPRECT_RULE:
|
||||||
|
return "mmPA_SC_CLIPRECT_RULE";
|
||||||
|
case mmPA_SC_MODE_CNTL_0:
|
||||||
|
return "mmPA_SC_MODE_CNTL_0";
|
||||||
|
case mmPA_SC_MODE_CNTL_1:
|
||||||
|
return "mmPA_SC_MODE_CNTL_1";
|
||||||
|
case mmPA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0:
|
||||||
|
return "mmPA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y0_0";
|
||||||
|
case mmPA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_0:
|
||||||
|
return "mmPA_SC_AA_SAMPLE_LOCS_PIXEL_X0Y1_0";
|
||||||
|
case mmPA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_0:
|
||||||
|
return "mmPA_SC_AA_SAMPLE_LOCS_PIXEL_X1Y0_0";
|
||||||
|
case mmPA_SC_AA_MASK_X0Y0_X1Y0:
|
||||||
|
return "mmPA_SC_AA_MASK_X0Y0_X1Y0";
|
||||||
|
case mmPA_SC_AA_MASK_X0Y1_X1Y1:
|
||||||
|
return "mmPA_SC_AA_MASK_X0Y1_X1Y1";
|
||||||
|
case mmPA_SC_CENTROID_PRIORITY_0:
|
||||||
|
return "mmPA_SC_CENTROID_PRIORITY_0";
|
||||||
|
case mmPA_SC_CENTROID_PRIORITY_1:
|
||||||
|
return "mmPA_SC_CENTROID_PRIORITY_1";
|
||||||
|
case mmPA_SC_AA_CONFIG:
|
||||||
|
return "mmPA_SC_AA_CONFIG";
|
||||||
|
case mmDB_RENDER_CONTROL:
|
||||||
|
return "mmDB_RENDER_CONTROL";
|
||||||
|
case mmDB_STENCIL_CONTROL:
|
||||||
|
return "mmDB_STENCIL_CONTROL";
|
||||||
|
case mmDB_STENCILREFMASK:
|
||||||
|
return "mmDB_STENCILREFMASK";
|
||||||
|
case mmDB_STENCILREFMASK_BF:
|
||||||
|
return "mmDB_STENCILREFMASK_BF";
|
||||||
|
case mmDB_STENCIL_CLEAR:
|
||||||
|
return "mmDB_STENCIL_CLEAR";
|
||||||
|
case mmDB_DEPTH_CLEAR:
|
||||||
|
return "mmDB_DEPTH_CLEAR";
|
||||||
|
case mmCB_TARGET_MASK:
|
||||||
|
return "mmCB_TARGET_MASK";
|
||||||
|
case mmDB_Z_INFO:
|
||||||
|
return "mmDB_Z_INFO";
|
||||||
|
case mmDB_STENCIL_INFO:
|
||||||
|
return "mmDB_STENCIL_INFO";
|
||||||
|
case mmDB_Z_READ_BASE:
|
||||||
|
return "mmDB_Z_READ_BASE";
|
||||||
|
case mmDB_STENCIL_READ_BASE:
|
||||||
|
return "mmDB_STENCIL_READ_BASE";
|
||||||
|
case mmDB_Z_WRITE_BASE:
|
||||||
|
return "mmDB_Z_WRITE_BASE";
|
||||||
|
case mmDB_STENCIL_WRITE_BASE:
|
||||||
|
return "mmDB_STENCIL_WRITE_BASE";
|
||||||
|
case mmDB_DEPTH_INFO:
|
||||||
|
return "mmDB_DEPTH_INFO";
|
||||||
|
case mmDB_DEPTH_VIEW:
|
||||||
|
return "mmDB_DEPTH_VIEW";
|
||||||
|
case mmDB_DEPTH_SLICE:
|
||||||
|
return "mmDB_DEPTH_SLICE";
|
||||||
|
case mmDB_DEPTH_SIZE:
|
||||||
|
return "mmDB_DEPTH_SIZE";
|
||||||
|
case mmTA_BC_BASE_ADDR:
|
||||||
|
return "mmTA_BC_BASE_ADDR";
|
||||||
|
case mmCB_BLEND_RED:
|
||||||
|
return "mmCB_BLEND_RED";
|
||||||
|
case mmCB_BLEND_GREEN:
|
||||||
|
return "mmCB_BLEND_GREEN";
|
||||||
|
case mmCB_BLEND_BLUE:
|
||||||
|
return "mmCB_BLEND_BLUE";
|
||||||
|
case mmDB_ALPHA_TO_MASK:
|
||||||
|
return "mmDB_ALPHA_TO_MASK";
|
||||||
|
case mmCB_BLEND0_CONTROL:
|
||||||
|
return "mmCB_BLEND0_CONTROL";
|
||||||
|
case mmCB_BLEND1_CONTROL:
|
||||||
|
return "mmCB_BLEND1_CONTROL";
|
||||||
|
case mmCB_BLEND2_CONTROL:
|
||||||
|
return "mmCB_BLEND2_CONTROL";
|
||||||
|
case mmCB_BLEND3_CONTROL:
|
||||||
|
return "mmCB_BLEND3_CONTROL";
|
||||||
|
case mmCB_BLEND4_CONTROL:
|
||||||
|
return "mmCB_BLEND4_CONTROL";
|
||||||
|
case mmCB_BLEND5_CONTROL:
|
||||||
|
return "mmCB_BLEND5_CONTROL";
|
||||||
|
case mmCB_BLEND6_CONTROL:
|
||||||
|
return "mmCB_BLEND6_CONTROL";
|
||||||
|
case mmCB_BLEND7_CONTROL:
|
||||||
|
return "mmCB_BLEND7_CONTROL";
|
||||||
|
case mmDB_HTILE_DATA_BASE:
|
||||||
|
return "mmDB_HTILE_DATA_BASE";
|
||||||
|
case mmDB_HTILE_SURFACE:
|
||||||
|
return "mmDB_HTILE_SURFACE";
|
||||||
|
case mmPA_SU_LINE_CNTL:
|
||||||
|
return "mmPA_SU_LINE_CNTL";
|
||||||
|
case mmPA_SC_VPORT_ZMIN_0:
|
||||||
|
return "mmPA_SC_VPORT_ZMIN_0";
|
||||||
|
case mmPA_SC_VPORT_ZMAX_0:
|
||||||
|
return "mmPA_SC_VPORT_ZMAX_0";
|
||||||
|
case mmPA_SC_VPORT_SCISSOR_0_TL:
|
||||||
|
return "mmPA_SC_VPORT_SCISSOR_0_TL";
|
||||||
|
case mmPA_SC_VPORT_SCISSOR_0_BR:
|
||||||
|
return "mmPA_SC_VPORT_SCISSOR_0_BR";
|
||||||
|
case mmPA_SC_GENERIC_SCISSOR_TL:
|
||||||
|
return "mmPA_SC_GENERIC_SCISSOR_TL";
|
||||||
|
case mmPA_SC_GENERIC_SCISSOR_BR:
|
||||||
|
return "mmPA_SC_GENERIC_SCISSOR_BR";
|
||||||
|
case mmPA_CL_VPORT_XSCALE:
|
||||||
|
return "mmPA_CL_VPORT_XSCALE";
|
||||||
|
case mmPA_CL_VPORT_YSCALE:
|
||||||
|
return "mmPA_CL_VPORT_YSCALE";
|
||||||
|
case mmPA_CL_VPORT_ZSCALE:
|
||||||
|
return "mmPA_CL_VPORT_ZSCALE";
|
||||||
|
case mmPA_CL_VPORT_XOFFSET:
|
||||||
|
return "mmPA_CL_VPORT_XOFFSET";
|
||||||
|
case mmPA_CL_VPORT_YOFFSET:
|
||||||
|
return "mmPA_CL_VPORT_YOFFSET";
|
||||||
|
case mmPA_CL_VPORT_ZOFFSET:
|
||||||
|
return "mmPA_CL_VPORT_ZOFFSET";
|
||||||
|
case mmPA_CL_VTE_CNTL:
|
||||||
|
return "mmPA_CL_VTE_CNTL";
|
||||||
|
case mmPA_SC_SCREEN_SCISSOR_TL:
|
||||||
|
return "mmPA_SC_SCREEN_SCISSOR_TL";
|
||||||
|
case mmPA_SC_SCREEN_SCISSOR_BR:
|
||||||
|
return "mmPA_SC_SCREEN_SCISSOR_BR";
|
||||||
|
case mmPA_SU_HARDWARE_SCREEN_OFFSET:
|
||||||
|
return "mmPA_SU_HARDWARE_SCREEN_OFFSET";
|
||||||
|
case mmPA_SU_VTX_CNTL:
|
||||||
|
return "mmPA_SU_VTX_CNTL";
|
||||||
|
case mmPA_CL_GB_VERT_CLIP_ADJ:
|
||||||
|
return "mmPA_CL_GB_VERT_CLIP_ADJ";
|
||||||
|
case mmPA_CL_GB_HORZ_CLIP_ADJ:
|
||||||
|
return "mmPA_CL_GB_HORZ_CLIP_ADJ";
|
||||||
|
case mmPA_CL_GB_VERT_DISC_ADJ:
|
||||||
|
return "mmPA_CL_GB_VERT_DISC_ADJ";
|
||||||
|
case mmPA_CL_GB_HORZ_DISC_ADJ:
|
||||||
|
return "mmPA_CL_GB_HORZ_DISC_ADJ";
|
||||||
|
case mmCB_COLOR_CONTROL:
|
||||||
|
return "mmCB_COLOR_CONTROL";
|
||||||
|
case mmSPI_SHADER_Z_FORMAT:
|
||||||
|
return "mmSPI_SHADER_Z_FORMAT";
|
||||||
|
case mmSPI_SHADER_COL_FORMAT:
|
||||||
|
return "mmSPI_SHADER_COL_FORMAT";
|
||||||
|
case mmPA_CL_VS_OUT_CNTL:
|
||||||
|
return "mmPA_CL_VS_OUT_CNTL";
|
||||||
|
case mmSPI_VS_OUT_CONFIG:
|
||||||
|
return "mmSPI_VS_OUT_CONFIG";
|
||||||
|
case mmSPI_SHADER_POS_FORMAT:
|
||||||
|
return "mmSPI_SHADER_POS_FORMAT";
|
||||||
|
case mmSPI_PS_INPUT_ENA:
|
||||||
|
return "mmSPI_PS_INPUT_ENA";
|
||||||
|
case mmSPI_PS_INPUT_ADDR:
|
||||||
|
return "mmSPI_PS_INPUT_ADDR";
|
||||||
|
case mmSPI_PS_IN_CONTROL:
|
||||||
|
return "mmSPI_PS_IN_CONTROL";
|
||||||
|
case mmSPI_BARYC_CNTL:
|
||||||
|
return "mmSPI_BARYC_CNTL";
|
||||||
|
case mmSPI_PS_INPUT_CNTL_0:
|
||||||
|
return "mmSPI_PS_INPUT_CNTL_0";
|
||||||
|
case mmSPI_PS_INPUT_CNTL_1:
|
||||||
|
return "mmSPI_PS_INPUT_CNTL_1";
|
||||||
|
case mmSPI_PS_INPUT_CNTL_2:
|
||||||
|
return "mmSPI_PS_INPUT_CNTL_2";
|
||||||
|
case mmSPI_PS_INPUT_CNTL_3:
|
||||||
|
return "mmSPI_PS_INPUT_CNTL_3";
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return "<UNK>";
|
||||||
|
}
|
||||||
|
} // namespace Core::Devtools::Gcn
|
169
src/core/devtools/gcn/gcn_shader_regs.cpp
Normal file
169
src/core/devtools/gcn/gcn_shader_regs.cpp
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "common/types.h"
|
||||||
|
#include "gcn/si_ci_vi_merged_offset.h"
|
||||||
|
|
||||||
|
using namespace Pal::Gfx6;
|
||||||
|
|
||||||
|
namespace Core::Devtools::Gcn {
|
||||||
|
const char* GetShaderRegName(u32 reg_offset) {
|
||||||
|
switch (reg_offset) {
|
||||||
|
case mmSPI_SHADER_PGM_LO_VS:
|
||||||
|
return "mmSPI_SHADER_PGM_LO_VS";
|
||||||
|
case mmSPI_SHADER_PGM_HI_VS:
|
||||||
|
return "mmSPI_SHADER_PGM_HI_VS";
|
||||||
|
case mmSPI_SHADER_PGM_LO_PS:
|
||||||
|
return "mmSPI_SHADER_PGM_LO_PS";
|
||||||
|
case mmSPI_SHADER_PGM_HI_PS:
|
||||||
|
return "mmSPI_SHADER_PGM_HI_PS";
|
||||||
|
case mmSPI_SHADER_PGM_RSRC1_VS:
|
||||||
|
return "mmSPI_SHADER_PGM_RSRC1_VS";
|
||||||
|
case mmSPI_SHADER_PGM_RSRC2_VS:
|
||||||
|
return "mmSPI_SHADER_PGM_RSRC2_VS";
|
||||||
|
case mmSPI_SHADER_PGM_RSRC3_VS__CI__VI:
|
||||||
|
return "mmSPI_SHADER_PGM_RSRC3_VS__CI__VI";
|
||||||
|
case mmSPI_SHADER_PGM_RSRC1_PS:
|
||||||
|
return "mmSPI_SHADER_PGM_RSRC1_PS";
|
||||||
|
case mmSPI_SHADER_PGM_RSRC2_PS:
|
||||||
|
return "mmSPI_SHADER_PGM_RSRC2_PS";
|
||||||
|
case mmSPI_SHADER_PGM_RSRC3_PS__CI__VI:
|
||||||
|
return "mmSPI_SHADER_PGM_RSRC3_PS__CI__VI";
|
||||||
|
case mmSPI_SHADER_USER_DATA_PS_0:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_PS_0";
|
||||||
|
case mmSPI_SHADER_USER_DATA_PS_1:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_PS_1";
|
||||||
|
case mmSPI_SHADER_USER_DATA_PS_2:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_PS_2";
|
||||||
|
case mmSPI_SHADER_USER_DATA_PS_3:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_PS_3";
|
||||||
|
case mmSPI_SHADER_USER_DATA_PS_4:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_PS_4";
|
||||||
|
case mmSPI_SHADER_USER_DATA_PS_5:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_PS_5";
|
||||||
|
case mmSPI_SHADER_USER_DATA_PS_6:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_PS_6";
|
||||||
|
case mmSPI_SHADER_USER_DATA_PS_7:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_PS_7";
|
||||||
|
case mmSPI_SHADER_USER_DATA_PS_8:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_PS_8";
|
||||||
|
case mmSPI_SHADER_USER_DATA_PS_9:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_PS_9";
|
||||||
|
case mmSPI_SHADER_USER_DATA_PS_10:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_PS_10";
|
||||||
|
case mmSPI_SHADER_USER_DATA_PS_11:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_PS_11";
|
||||||
|
case mmSPI_SHADER_USER_DATA_PS_12:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_PS_12";
|
||||||
|
case mmSPI_SHADER_USER_DATA_PS_13:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_PS_13";
|
||||||
|
case mmSPI_SHADER_USER_DATA_PS_14:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_PS_14";
|
||||||
|
case mmSPI_SHADER_USER_DATA_PS_15:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_PS_15";
|
||||||
|
case mmCOMPUTE_TMPRING_SIZE:
|
||||||
|
return "mmCOMPUTE_TMPRING_SIZE";
|
||||||
|
case mmCOMPUTE_PGM_LO:
|
||||||
|
return "mmCOMPUTE_PGM_LO";
|
||||||
|
case mmCOMPUTE_PGM_HI:
|
||||||
|
return "mmCOMPUTE_PGM_HI";
|
||||||
|
case mmCOMPUTE_PGM_RSRC1:
|
||||||
|
return "mmCOMPUTE_PGM_RSRC1";
|
||||||
|
case mmCOMPUTE_PGM_RSRC2:
|
||||||
|
return "mmCOMPUTE_PGM_RSRC2";
|
||||||
|
case mmCOMPUTE_USER_DATA_0:
|
||||||
|
return "mmCOMPUTE_USER_DATA_0";
|
||||||
|
case mmCOMPUTE_USER_DATA_1:
|
||||||
|
return "mmCOMPUTE_USER_DATA_1";
|
||||||
|
case mmCOMPUTE_USER_DATA_2:
|
||||||
|
return "mmCOMPUTE_USER_DATA_2";
|
||||||
|
case mmCOMPUTE_USER_DATA_3:
|
||||||
|
return "mmCOMPUTE_USER_DATA_3";
|
||||||
|
case mmCOMPUTE_USER_DATA_4:
|
||||||
|
return "mmCOMPUTE_USER_DATA_4";
|
||||||
|
case mmCOMPUTE_USER_DATA_5:
|
||||||
|
return "mmCOMPUTE_USER_DATA_5";
|
||||||
|
case mmCOMPUTE_USER_DATA_6:
|
||||||
|
return "mmCOMPUTE_USER_DATA_6";
|
||||||
|
case mmCOMPUTE_USER_DATA_7:
|
||||||
|
return "mmCOMPUTE_USER_DATA_7";
|
||||||
|
case mmCOMPUTE_USER_DATA_8:
|
||||||
|
return "mmCOMPUTE_USER_DATA_8";
|
||||||
|
case mmCOMPUTE_USER_DATA_9:
|
||||||
|
return "mmCOMPUTE_USER_DATA_9";
|
||||||
|
case mmCOMPUTE_USER_DATA_10:
|
||||||
|
return "mmCOMPUTE_USER_DATA_10";
|
||||||
|
case mmCOMPUTE_USER_DATA_11:
|
||||||
|
return "mmCOMPUTE_USER_DATA_11";
|
||||||
|
case mmCOMPUTE_USER_DATA_12:
|
||||||
|
return "mmCOMPUTE_USER_DATA_12";
|
||||||
|
case mmCOMPUTE_USER_DATA_13:
|
||||||
|
return "mmCOMPUTE_USER_DATA_13";
|
||||||
|
case mmCOMPUTE_USER_DATA_14:
|
||||||
|
return "mmCOMPUTE_USER_DATA_14";
|
||||||
|
case mmCOMPUTE_USER_DATA_15:
|
||||||
|
return "mmCOMPUTE_USER_DATA_15";
|
||||||
|
case mmCOMPUTE_NUM_THREAD_X:
|
||||||
|
return "mmCOMPUTE_NUM_THREAD_X";
|
||||||
|
case mmCOMPUTE_NUM_THREAD_Y:
|
||||||
|
return "mmCOMPUTE_NUM_THREAD_Y";
|
||||||
|
case mmCOMPUTE_NUM_THREAD_Z:
|
||||||
|
return "mmCOMPUTE_NUM_THREAD_Z";
|
||||||
|
case mmCOMPUTE_STATIC_THREAD_MGMT_SE0:
|
||||||
|
return "mmCOMPUTE_STATIC_THREAD_MGMT_SE0";
|
||||||
|
case mmCOMPUTE_STATIC_THREAD_MGMT_SE1:
|
||||||
|
return "mmCOMPUTE_STATIC_THREAD_MGMT_SE1";
|
||||||
|
case mmCOMPUTE_RESOURCE_LIMITS:
|
||||||
|
return "mmCOMPUTE_RESOURCE_LIMITS";
|
||||||
|
case mmSPI_SHADER_USER_DATA_VS_0:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_VS_0";
|
||||||
|
case mmSPI_SHADER_USER_DATA_VS_1:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_VS_1";
|
||||||
|
case mmSPI_SHADER_USER_DATA_VS_2:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_VS_2";
|
||||||
|
case mmSPI_SHADER_USER_DATA_VS_3:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_VS_3";
|
||||||
|
case mmSPI_SHADER_USER_DATA_VS_4:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_VS_4";
|
||||||
|
case mmSPI_SHADER_USER_DATA_VS_5:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_VS_5";
|
||||||
|
case mmSPI_SHADER_USER_DATA_VS_6:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_VS_6";
|
||||||
|
case mmSPI_SHADER_USER_DATA_VS_7:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_VS_7";
|
||||||
|
case mmSPI_SHADER_USER_DATA_VS_8:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_VS_8";
|
||||||
|
case mmSPI_SHADER_USER_DATA_VS_9:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_VS_9";
|
||||||
|
case mmSPI_SHADER_USER_DATA_VS_10:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_VS_10";
|
||||||
|
case mmSPI_SHADER_USER_DATA_VS_11:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_VS_11";
|
||||||
|
case mmSPI_SHADER_USER_DATA_VS_12:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_VS_12";
|
||||||
|
case mmSPI_SHADER_USER_DATA_VS_13:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_VS_13";
|
||||||
|
case mmSPI_SHADER_USER_DATA_VS_14:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_VS_14";
|
||||||
|
case mmSPI_SHADER_USER_DATA_VS_15:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_VS_15";
|
||||||
|
case mmSPI_SHADER_USER_DATA_HS_0:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_HS_0";
|
||||||
|
case mmSPI_SHADER_USER_DATA_HS_1:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_HS_1";
|
||||||
|
case mmSPI_SHADER_USER_DATA_HS_9:
|
||||||
|
return "mmSPI_SHADER_USER_DATA_HS_9";
|
||||||
|
case mmSPI_SHADER_PGM_RSRC3_GS__CI__VI:
|
||||||
|
return "mmSPI_SHADER_PGM_RSRC3_GS__CI__VI";
|
||||||
|
case mmSPI_SHADER_PGM_RSRC3_ES__CI__VI:
|
||||||
|
return "mmSPI_SHADER_PGM_RSRC3_ES__CI__VI";
|
||||||
|
case mmSPI_SHADER_PGM_RSRC3_LS__CI__VI:
|
||||||
|
return "mmSPI_SHADER_PGM_RSRC3_LS__CI__VI";
|
||||||
|
case mmSPI_SHADER_LATE_ALLOC_VS__CI__VI:
|
||||||
|
return "mmSPI_SHADER_LATE_ALLOC_VS__CI__VI";
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return "<UNK>";
|
||||||
|
}
|
||||||
|
} // namespace Core::Devtools::Gcn
|
189
src/core/devtools/layer.cpp
Normal file
189
src/core/devtools/layer.cpp
Normal file
|
@ -0,0 +1,189 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include "common/config.h"
|
||||||
|
#include "common/singleton.h"
|
||||||
|
#include "common/types.h"
|
||||||
|
#include "core/debug_state.h"
|
||||||
|
#include "imgui/imgui_std.h"
|
||||||
|
#include "imgui_internal.h"
|
||||||
|
#include "layer.h"
|
||||||
|
#include "widget/frame_dump.h"
|
||||||
|
#include "widget/frame_graph.h"
|
||||||
|
|
||||||
|
using namespace ImGui;
|
||||||
|
using namespace Core::Devtools;
|
||||||
|
using L = Core::Devtools::Layer;
|
||||||
|
|
||||||
|
static bool show_simple_fps = false;
|
||||||
|
static bool show_advanced_debug = false;
|
||||||
|
|
||||||
|
static int dump_frame_count = 1;
|
||||||
|
|
||||||
|
static Widget::FrameGraph frame_graph;
|
||||||
|
static std::vector<Widget::FrameDumpViewer> frame_viewers;
|
||||||
|
|
||||||
|
void L::DrawMenuBar() {
|
||||||
|
const auto& ctx = *GImGui;
|
||||||
|
const auto& io = ctx.IO;
|
||||||
|
|
||||||
|
auto isSystemPaused = DebugState.IsGuestThreadsPaused();
|
||||||
|
|
||||||
|
if (BeginMainMenuBar()) {
|
||||||
|
if (BeginMenu("Options")) {
|
||||||
|
if (MenuItemEx("Emulator Paused", nullptr, nullptr, isSystemPaused)) {
|
||||||
|
if (isSystemPaused) {
|
||||||
|
DebugState.ResumeGuestThreads();
|
||||||
|
} else {
|
||||||
|
DebugState.PauseGuestThreads();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
if (BeginMenu("GPU Tools")) {
|
||||||
|
MenuItem("Show frame info", nullptr, &frame_graph.is_open);
|
||||||
|
if (BeginMenu("Dump frames")) {
|
||||||
|
SliderInt("Count", &dump_frame_count, 1, 5);
|
||||||
|
if (MenuItem("Dump", "Ctrl+Alt+F9", nullptr, !DebugState.DumpingCurrentFrame())) {
|
||||||
|
DebugState.RequestFrameDump(dump_frame_count);
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
EndMainMenuBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsKeyPressed(ImGuiKey_F9, false)) {
|
||||||
|
if (io.KeyCtrl && io.KeyAlt) {
|
||||||
|
if (!DebugState.ShouldPauseInSubmit()) {
|
||||||
|
DebugState.RequestFrameDump(dump_frame_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!io.KeyCtrl && !io.KeyAlt) {
|
||||||
|
if (isSystemPaused) {
|
||||||
|
DebugState.ResumeGuestThreads();
|
||||||
|
} else {
|
||||||
|
DebugState.PauseGuestThreads();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void L::DrawAdvanced() {
|
||||||
|
DrawMenuBar();
|
||||||
|
|
||||||
|
const auto& ctx = *GImGui;
|
||||||
|
const auto& io = ctx.IO;
|
||||||
|
|
||||||
|
auto isSystemPaused = DebugState.IsGuestThreadsPaused();
|
||||||
|
|
||||||
|
frame_graph.Draw();
|
||||||
|
|
||||||
|
if (isSystemPaused) {
|
||||||
|
GetForegroundDrawList(GetMainViewport())
|
||||||
|
->AddText({10.0f, io.DisplaySize.y - 40.0f}, IM_COL32_WHITE, "Emulator paused");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DebugState.should_show_frame_dump) {
|
||||||
|
DebugState.should_show_frame_dump = false;
|
||||||
|
std::unique_lock lock{DebugState.frame_dump_list_mutex};
|
||||||
|
while (!DebugState.frame_dump_list.empty()) {
|
||||||
|
auto frame_dump = std::move(DebugState.frame_dump_list.back());
|
||||||
|
DebugState.frame_dump_list.pop_back();
|
||||||
|
frame_viewers.emplace_back(frame_dump);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it = frame_viewers.begin(); it != frame_viewers.end();) {
|
||||||
|
if (it->is_open) {
|
||||||
|
it->Draw();
|
||||||
|
++it;
|
||||||
|
} else {
|
||||||
|
it = frame_viewers.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void L::DrawSimple() {
|
||||||
|
const auto io = GetIO();
|
||||||
|
Text("Frame time: %.3f ms (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void L::SetupSettings() {
|
||||||
|
frame_graph.is_open = true;
|
||||||
|
|
||||||
|
ImGuiSettingsHandler handler{};
|
||||||
|
handler.TypeName = "DevtoolsLayer";
|
||||||
|
handler.TypeHash = ImHashStr(handler.TypeName);
|
||||||
|
handler.ReadOpenFn = [](ImGuiContext*, ImGuiSettingsHandler*, const char* name) {
|
||||||
|
return std::string_view("Data") == name ? (void*)1 : nullptr;
|
||||||
|
};
|
||||||
|
handler.ReadLineFn = [](ImGuiContext*, ImGuiSettingsHandler*, void*, const char* line) {
|
||||||
|
int v;
|
||||||
|
if (sscanf(line, "show_simple_fps=%d", &v) == 1) {
|
||||||
|
show_simple_fps = v != 0;
|
||||||
|
} 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) {
|
||||||
|
buf->appendf("[%s][Data]\n", handler->TypeName);
|
||||||
|
buf->appendf("show_simple_fps=%d\n", show_simple_fps);
|
||||||
|
buf->appendf("show_advanced_debug=%d\n", show_advanced_debug);
|
||||||
|
buf->appendf("show_frame_graph=%d\n", frame_graph.is_open);
|
||||||
|
buf->appendf("dump_frame_count=%d\n", dump_frame_count);
|
||||||
|
buf->append("\n");
|
||||||
|
};
|
||||||
|
AddSettingsHandler(&handler);
|
||||||
|
|
||||||
|
const ImGuiID dock_id = ImHashStr("FrameDumpDock");
|
||||||
|
DockBuilderAddNode(dock_id, 0);
|
||||||
|
DockBuilderSetNodePos(dock_id, ImVec2{50.0, 50.0});
|
||||||
|
DockBuilderFinish(dock_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void L::Draw() {
|
||||||
|
const auto io = GetIO();
|
||||||
|
PushID("DevtoolsLayer");
|
||||||
|
|
||||||
|
if (!DebugState.IsGuestThreadsPaused()) {
|
||||||
|
const auto fn = DebugState.flip_frame_count.load();
|
||||||
|
frame_graph.AddFrame(fn, io.DeltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsKeyPressed(ImGuiKey_F10, false)) {
|
||||||
|
if (io.KeyCtrl) {
|
||||||
|
show_advanced_debug = !show_advanced_debug;
|
||||||
|
} else {
|
||||||
|
show_simple_fps = !show_simple_fps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_simple_fps) {
|
||||||
|
SetWindowPos("Video Info", {999999.0f, 0.0f}, ImGuiCond_FirstUseEver);
|
||||||
|
if (Begin("Video Info", nullptr,
|
||||||
|
ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDecoration |
|
||||||
|
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking)) {
|
||||||
|
KeepWindowInside();
|
||||||
|
DrawSimple();
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_advanced_debug) {
|
||||||
|
PushFont(io.Fonts->Fonts[0]);
|
||||||
|
PushID("DevtoolsLayer");
|
||||||
|
DrawAdvanced();
|
||||||
|
PopID();
|
||||||
|
PopFont();
|
||||||
|
}
|
||||||
|
|
||||||
|
PopID();
|
||||||
|
}
|
24
src/core/devtools/layer.h
Normal file
24
src/core/devtools/layer.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "imgui/imgui_layer.h"
|
||||||
|
|
||||||
|
namespace Core::Devtools {
|
||||||
|
|
||||||
|
class Layer final : public ImGui::Layer {
|
||||||
|
|
||||||
|
static void DrawMenuBar();
|
||||||
|
|
||||||
|
static void DrawAdvanced();
|
||||||
|
|
||||||
|
static void DrawSimple();
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void SetupSettings();
|
||||||
|
|
||||||
|
void Draw() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core::Devtools
|
1214
src/core/devtools/widget/cmd_list.cpp
Normal file
1214
src/core/devtools/widget/cmd_list.cpp
Normal file
File diff suppressed because it is too large
Load diff
60
src/core/devtools/widget/cmd_list.h
Normal file
60
src/core/devtools/widget/cmd_list.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
// Credits to https://github.com/psucien/tlg-emu-tools/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/types.h"
|
||||||
|
#include "video_core/buffer_cache/buffer_cache.h"
|
||||||
|
|
||||||
|
namespace AmdGpu {
|
||||||
|
union PM4Type3Header;
|
||||||
|
enum class PM4ItOpcode : u32;
|
||||||
|
} // namespace AmdGpu
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
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};
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<BatchInfo> batches{};
|
||||||
|
uintptr_t cmdb_addr;
|
||||||
|
size_t cmdb_size;
|
||||||
|
|
||||||
|
int batch_bp{-1};
|
||||||
|
int vqid{255};
|
||||||
|
|
||||||
|
void OnNop(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||||
|
void OnSetBase(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||||
|
void OnSetContextReg(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||||
|
void OnSetShReg(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||||
|
void OnDispatch(AmdGpu::PM4Type3Header const* header, u32 const* body);
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CmdListViewer(const std::vector<u32>& cmd_list);
|
||||||
|
|
||||||
|
void Draw();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core::Devtools::Widget
|
52
src/core/devtools/widget/frame_dump.cpp
Normal file
52
src/core/devtools/widget/frame_dump.cpp
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <magic_enum.hpp>
|
||||||
|
|
||||||
|
#include "cmd_list.h"
|
||||||
|
#include "frame_dump.h"
|
||||||
|
#include "imgui_internal.h"
|
||||||
|
|
||||||
|
using namespace ImGui;
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
FrameDumpViewer::FrameDumpViewer(DebugStateType::FrameDump frame_dump)
|
||||||
|
: frame_dump(std::move(frame_dump)) {
|
||||||
|
static int unique_id = 0;
|
||||||
|
id = unique_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FrameDumpViewer::Draw() {
|
||||||
|
if (!is_open) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char name[32];
|
||||||
|
snprintf(name, sizeof(name), "Frame #%d dump", id);
|
||||||
|
static ImGuiID dock_id = ImHashStr("FrameDumpDock");
|
||||||
|
SetNextWindowDockID(dock_id, ImGuiCond_Appearing);
|
||||||
|
if (Begin(name, &is_open, ImGuiWindowFlags_NoSavedSettings)) {
|
||||||
|
if (IsWindowAppearing()) {
|
||||||
|
auto window = GetCurrentWindow();
|
||||||
|
SetWindowSize(window, ImVec2{450.0f, 500.0f});
|
||||||
|
}
|
||||||
|
if (BeginTabBar("Queues")) {
|
||||||
|
for (auto& cmd : frame_dump.queues) {
|
||||||
|
char tab_name[64];
|
||||||
|
snprintf(tab_name, sizeof(tab_name), "%s - %d %d",
|
||||||
|
magic_enum::enum_name(cmd.type).data(), cmd.submit_num, cmd.num2);
|
||||||
|
if (BeginTabItem(tab_name)) {
|
||||||
|
CmdListViewer(cmd.data).Draw();
|
||||||
|
EndTabItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EndTabBar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core::Devtools::Widget
|
22
src/core/devtools/widget/frame_dump.h
Normal file
22
src/core/devtools/widget/frame_dump.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/debug_state.h"
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
class FrameDumpViewer {
|
||||||
|
DebugStateType::FrameDump frame_dump;
|
||||||
|
int id;
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool is_open = true;
|
||||||
|
|
||||||
|
explicit FrameDumpViewer(DebugStateType::FrameDump frame_dump);
|
||||||
|
|
||||||
|
void Draw();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core::Devtools::Widget
|
99
src/core/devtools/widget/frame_graph.cpp
Normal file
99
src/core/devtools/widget/frame_graph.cpp
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "frame_graph.h"
|
||||||
|
|
||||||
|
#include "common/config.h"
|
||||||
|
#include "common/singleton.h"
|
||||||
|
#include "core/debug_state.h"
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "imgui_internal.h"
|
||||||
|
|
||||||
|
using namespace ImGui;
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
constexpr float TARGET_FPS = 60.0f;
|
||||||
|
constexpr float BAR_WIDTH_MULT = 1.4f;
|
||||||
|
constexpr float BAR_HEIGHT_MULT = 1.25f;
|
||||||
|
constexpr float FRAME_GRAPH_PADDING_Y = 3.0f;
|
||||||
|
constexpr static float FRAME_GRAPH_HEIGHT = 50.0f;
|
||||||
|
|
||||||
|
void FrameGraph::Draw() {
|
||||||
|
if (!is_open) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SetNextWindowSize({340.0, 185.0f}, ImGuiCond_FirstUseEver);
|
||||||
|
if (Begin("Video debug info", &is_open)) {
|
||||||
|
const auto& ctx = *GImGui;
|
||||||
|
const auto& io = ctx.IO;
|
||||||
|
const auto& window = *ctx.CurrentWindow;
|
||||||
|
auto& draw_list = *window.DrawList;
|
||||||
|
|
||||||
|
auto isSystemPaused = DebugState.IsGuestThreadsPaused();
|
||||||
|
|
||||||
|
static float deltaTime;
|
||||||
|
static float frameRate;
|
||||||
|
|
||||||
|
if (!isSystemPaused) {
|
||||||
|
deltaTime = io.DeltaTime * 1000.0f;
|
||||||
|
frameRate = 1000.0f / deltaTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
Text("Frame time: %.3f ms (%.1f FPS)", deltaTime, frameRate);
|
||||||
|
Text("Flip frame: %d Gnm submit frame: %d", DebugState.flip_frame_count.load(),
|
||||||
|
DebugState.gnm_frame_count.load());
|
||||||
|
SeparatorText("Frame graph");
|
||||||
|
|
||||||
|
const float full_width = GetContentRegionAvail().x;
|
||||||
|
// Frame graph - inspired by
|
||||||
|
// https://asawicki.info/news_1758_an_idea_for_visualization_of_frame_times
|
||||||
|
auto pos = GetCursorScreenPos();
|
||||||
|
const ImVec2 size{full_width, FRAME_GRAPH_HEIGHT + FRAME_GRAPH_PADDING_Y * 2.0f};
|
||||||
|
ItemSize(size);
|
||||||
|
if (!ItemAdd({pos, pos + size}, GetID("FrameGraph"))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float target_dt = 1.0f / (TARGET_FPS * (float)Config::vblankDiv());
|
||||||
|
float cur_pos_x = pos.x + full_width;
|
||||||
|
pos.y += FRAME_GRAPH_PADDING_Y;
|
||||||
|
const float final_pos_y = pos.y + FRAME_GRAPH_HEIGHT;
|
||||||
|
|
||||||
|
draw_list.AddRectFilled({pos.x, pos.y - FRAME_GRAPH_PADDING_Y},
|
||||||
|
{pos.x + full_width, final_pos_y + FRAME_GRAPH_PADDING_Y},
|
||||||
|
IM_COL32(0x33, 0x33, 0x33, 0xFF));
|
||||||
|
draw_list.PushClipRect({pos.x, pos.y}, {pos.x + full_width, final_pos_y}, true);
|
||||||
|
for (u32 i = 0; i < FRAME_BUFFER_SIZE; ++i) {
|
||||||
|
const auto& frame_info = frame_list[(DebugState.GetFrameNum() - i) % FRAME_BUFFER_SIZE];
|
||||||
|
const float dt_factor = target_dt / frame_info.delta;
|
||||||
|
|
||||||
|
const float width = std::ceil(BAR_WIDTH_MULT / dt_factor);
|
||||||
|
const float height =
|
||||||
|
std::min(std::log2(BAR_HEIGHT_MULT / dt_factor) / 3.0f, 1.0f) * FRAME_GRAPH_HEIGHT;
|
||||||
|
|
||||||
|
ImU32 color;
|
||||||
|
if (dt_factor >= 0.95f) { // BLUE
|
||||||
|
color = IM_COL32(0x33, 0x33, 0xFF, 0xFF);
|
||||||
|
} else if (dt_factor >= 0.5f) { // GREEN <> YELLOW
|
||||||
|
float t = 1.0f - (dt_factor - 0.5f) * 2.0f;
|
||||||
|
int r = (int)(0xFF * t);
|
||||||
|
color = IM_COL32(r, 0xFF, 0, 0xFF);
|
||||||
|
} else { // YELLOW <> RED
|
||||||
|
float t = dt_factor * 2.0f;
|
||||||
|
int g = (int)(0xFF * t);
|
||||||
|
color = IM_COL32(0xFF, g, 0, 0xFF);
|
||||||
|
}
|
||||||
|
draw_list.AddRectFilled({cur_pos_x - width, final_pos_y - height},
|
||||||
|
{cur_pos_x, final_pos_y}, color);
|
||||||
|
cur_pos_x -= width;
|
||||||
|
if (cur_pos_x < width) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
draw_list.PopClipRect();
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core::Devtools::Widget
|
29
src/core/devtools/widget/frame_graph.h
Normal file
29
src/core/devtools/widget/frame_graph.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
class FrameGraph {
|
||||||
|
static constexpr u32 FRAME_BUFFER_SIZE = 1024;
|
||||||
|
struct FrameInfo {
|
||||||
|
u32 num;
|
||||||
|
float delta;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::array<FrameInfo, FRAME_BUFFER_SIZE> frame_list{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool is_open = true;
|
||||||
|
|
||||||
|
void Draw();
|
||||||
|
|
||||||
|
void AddFrame(u32 num, float delta) {
|
||||||
|
frame_list[num % FRAME_BUFFER_SIZE] = FrameInfo{num, delta};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core::Devtools::Widget
|
|
@ -11,6 +11,7 @@
|
||||||
#include "common/path_util.h"
|
#include "common/path_util.h"
|
||||||
#include "common/slot_vector.h"
|
#include "common/slot_vector.h"
|
||||||
#include "core/address_space.h"
|
#include "core/address_space.h"
|
||||||
|
#include "core/debug_state.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/kernel/libkernel.h"
|
#include "core/libraries/kernel/libkernel.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
|
@ -320,20 +321,6 @@ static void WaitGpuIdle() {
|
||||||
cv_lock.wait(lock, [] { return submission_lock == 0; });
|
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
|
// Write a special ending NOP packet with N DWs data block
|
||||||
template <u32 data_block_size>
|
template <u32 data_block_size>
|
||||||
static inline u32* WriteTrailingNop(u32* cmdbuf) {
|
static inline u32* WriteTrailingNop(u32* cmdbuf) {
|
||||||
|
@ -507,16 +494,18 @@ void PS4_SYSV_ABI sceGnmDingDong(u32 gnm_vqid, u32 next_offs_dw) {
|
||||||
|
|
||||||
WaitGpuIdle();
|
WaitGpuIdle();
|
||||||
|
|
||||||
/* Suspend logic goes here */
|
if (DebugState.ShouldPauseInSubmit()) {
|
||||||
|
DebugState.PauseGuestThreads();
|
||||||
|
}
|
||||||
|
|
||||||
auto vqid = gnm_vqid - 1;
|
auto vqid = gnm_vqid - 1;
|
||||||
auto& asc_queue = asc_queues[{vqid}];
|
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_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
|
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;
|
: (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 auto last_frame_num = -1LL;
|
||||||
static u32 seq_num{};
|
static u32 seq_num{};
|
||||||
if (last_frame_num == frames_submitted) {
|
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};
|
acb = {indirect_buffer->Address<const u32>(), indirect_buffer->ib_size};
|
||||||
}
|
}
|
||||||
|
|
||||||
// File name format is: <queue>_<queue num>_<submit_num>
|
using namespace DebugStateType;
|
||||||
DumpCommandList(acb, fmt::format("acb_{}_{}", gnm_vqid, seq_num));
|
|
||||||
|
DebugState.PushQueueDump({
|
||||||
|
.type = QueueType::acb,
|
||||||
|
.submit_num = seq_num,
|
||||||
|
.num2 = gnm_vqid,
|
||||||
|
.data = {acb.begin(), acb.end()},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
liverpool->SubmitAsc(vqid, acb_span);
|
liverpool->SubmitAsc(vqid, acb_span);
|
||||||
|
@ -2108,7 +2103,9 @@ s32 PS4_SYSV_ABI sceGnmSubmitCommandBuffers(u32 count, const u32* dcb_gpu_addrs[
|
||||||
|
|
||||||
WaitGpuIdle();
|
WaitGpuIdle();
|
||||||
|
|
||||||
/* Suspend logic goes here */
|
if (DebugState.ShouldPauseInSubmit()) {
|
||||||
|
DebugState.PauseGuestThreads();
|
||||||
|
}
|
||||||
|
|
||||||
if (send_init_packet) {
|
if (send_init_packet) {
|
||||||
if (sdk_version <= 0x1ffffffu) {
|
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 dcb_size_dw = dcb_sizes_in_bytes[cbpair] >> 2;
|
||||||
const auto ccb_size_dw = ccb_size_in_bytes >> 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& dcb_span = std::span{dcb_gpu_addrs[cbpair], dcb_size_dw};
|
||||||
const auto& ccb_span = std::span<const u32>{ccb, ccb_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 auto last_frame_num = -1LL;
|
||||||
static u32 seq_num{};
|
static u32 seq_num{};
|
||||||
if (last_frame_num == frames_submitted && cbpair == 0) {
|
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;
|
seq_num = 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
// File name format is: <queue>_<submit num>_<buffer_in_submit>
|
using DebugStateType::QueueType;
|
||||||
DumpCommandList(dcb_span, fmt::format("dcb_{}_{}", seq_num, cbpair));
|
|
||||||
DumpCommandList(ccb_span, fmt::format("ccb_{}_{}", seq_num, cbpair));
|
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);
|
liverpool->SubmitGfx(dcb_span, ccb_span);
|
||||||
|
@ -2166,6 +2174,7 @@ int PS4_SYSV_ABI sceGnmSubmitDone() {
|
||||||
liverpool->SubmitDone();
|
liverpool->SubmitDone();
|
||||||
send_init_packet = true;
|
send_init_packet = true;
|
||||||
++frames_submitted;
|
++frames_submitted;
|
||||||
|
DebugState.IncGnmFrameNum();
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,13 @@
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
|
#include "core/debug_state.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/kernel/libkernel.h"
|
#include "core/libraries/kernel/libkernel.h"
|
||||||
#include "core/libraries/kernel/thread_management.h"
|
#include "core/libraries/kernel/thread_management.h"
|
||||||
#include "core/libraries/kernel/threads/threads.h"
|
#include "core/libraries/kernel/threads/threads.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
#include "core/linker.h"
|
#include "core/linker.h"
|
||||||
#include "core/system.h"
|
|
||||||
#include "core/tls.h"
|
#include "core/tls.h"
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
@ -989,7 +989,7 @@ static void cleanup_thread(void* arg) {
|
||||||
}
|
}
|
||||||
Core::SetTcbBase(nullptr);
|
Core::SetTcbBase(nullptr);
|
||||||
thread->is_almost_done = true;
|
thread->is_almost_done = true;
|
||||||
Common::Singleton<SystemState>::Instance()->RemoveCurrentThreadFromGuestList();
|
DebugState.RemoveCurrentThreadFromGuestList();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* run_thread(void* arg) {
|
static void* run_thread(void* arg) {
|
||||||
|
@ -1000,7 +1000,7 @@ static void* run_thread(void* arg) {
|
||||||
g_pthread_self = thread;
|
g_pthread_self = thread;
|
||||||
pthread_cleanup_push(cleanup_thread, thread);
|
pthread_cleanup_push(cleanup_thread, thread);
|
||||||
thread->is_started = true;
|
thread->is_started = true;
|
||||||
Common::Singleton<SystemState>::Instance()->AddCurrentThreadToGuestList();
|
DebugState.AddCurrentThreadToGuestList();
|
||||||
ret = linker->ExecuteGuest(thread->entry, thread->arg);
|
ret = linker->ExecuteGuest(thread->entry, thread->arg);
|
||||||
pthread_cleanup_pop(1);
|
pthread_cleanup_pop(1);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
|
#include "core/debug_state.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/kernel/time_management.h"
|
#include "core/libraries/kernel/time_management.h"
|
||||||
#include "core/libraries/videoout/driver.h"
|
#include "core/libraries/videoout/driver.h"
|
||||||
#include "core/platform.h"
|
#include "core/platform.h"
|
||||||
#include "core/system.h"
|
|
||||||
#include "video_core/renderer_vulkan/renderer_vulkan.h"
|
#include "video_core/renderer_vulkan/renderer_vulkan.h"
|
||||||
|
|
||||||
extern std::unique_ptr<Vulkan::RendererVulkan> renderer;
|
extern std::unique_ptr<Vulkan::RendererVulkan> renderer;
|
||||||
|
@ -266,8 +266,6 @@ void VideoOutDriver::PresentThread(std::stop_token token) {
|
||||||
|
|
||||||
Common::AccurateTimer timer{vblank_period};
|
Common::AccurateTimer timer{vblank_period};
|
||||||
|
|
||||||
auto systemState = Common::Singleton<SystemState>::Instance();
|
|
||||||
|
|
||||||
const auto receive_request = [this] -> Request {
|
const auto receive_request = [this] -> Request {
|
||||||
std::scoped_lock lk{mutex};
|
std::scoped_lock lk{mutex};
|
||||||
if (!requests.empty()) {
|
if (!requests.empty()) {
|
||||||
|
@ -287,7 +285,7 @@ void VideoOutDriver::PresentThread(std::stop_token token) {
|
||||||
if (vblank_status.count % (main_port.flip_rate + 1) == 0) {
|
if (vblank_status.count % (main_port.flip_rate + 1) == 0) {
|
||||||
const auto request = receive_request();
|
const auto request = receive_request();
|
||||||
if (!request) {
|
if (!request) {
|
||||||
if (!main_port.is_open || systemState->IsGuestThreadsPaused()) {
|
if (!main_port.is_open || DebugState.IsGuestThreadsPaused()) {
|
||||||
DrawBlankFrame();
|
DrawBlankFrame();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "core/tls.h"
|
#include "core/tls.h"
|
||||||
#include "core/virtual_memory.h"
|
#include "core/virtual_memory.h"
|
||||||
#include "system.h"
|
#include "debug_state.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ void Linker::Execute() {
|
||||||
|
|
||||||
// Init primary thread.
|
// Init primary thread.
|
||||||
Common::SetCurrentThreadName("GAME_MainThread");
|
Common::SetCurrentThreadName("GAME_MainThread");
|
||||||
Common::Singleton<SystemState>::Instance()->AddCurrentThreadToGuestList();
|
DebugState.AddCurrentThreadToGuestList();
|
||||||
Libraries::Kernel::pthreadInitSelfMainThread();
|
Libraries::Kernel::pthreadInitSelfMainThread();
|
||||||
EnsureThreadInitialized(true);
|
EnsureThreadInitialized(true);
|
||||||
|
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include "common/assert.h"
|
|
||||||
#include "common/native_clock.h"
|
|
||||||
#include "libraries/kernel/event_queues.h"
|
|
||||||
#include "libraries/kernel/time_management.h"
|
|
||||||
#include "libraries/system/msgdialog.h"
|
|
||||||
#include "system.h"
|
|
||||||
|
|
||||||
void SystemState::AddCurrentThreadToGuestList() {
|
|
||||||
std::lock_guard lock{guest_threads_mutex};
|
|
||||||
ThreadID id;
|
|
||||||
#ifdef _WIN32
|
|
||||||
id = GetCurrentThreadId();
|
|
||||||
#else
|
|
||||||
id = pthread_self();
|
|
||||||
#endif
|
|
||||||
guest_threads.push_back(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemState::RemoveCurrentThreadFromGuestList() {
|
|
||||||
std::lock_guard lock{guest_threads_mutex};
|
|
||||||
ThreadID id;
|
|
||||||
#ifdef _WIN32
|
|
||||||
id = GetCurrentThreadId();
|
|
||||||
#else
|
|
||||||
id = pthread_self();
|
|
||||||
#endif
|
|
||||||
std::erase_if(guest_threads, [&](const ThreadID& v) { return v == id; });
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemState::PauseGuestThreads() {
|
|
||||||
using namespace Libraries::MsgDialog;
|
|
||||||
std::lock_guard lock{guest_threads_mutex};
|
|
||||||
if (is_guest_threads_paused) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& id : guest_threads) {
|
|
||||||
#ifdef _WIN32
|
|
||||||
const HANDLE hd = OpenThread(THREAD_SUSPEND_RESUME, FALSE, id);
|
|
||||||
SuspendThread(hd);
|
|
||||||
CloseHandle(hd);
|
|
||||||
#else
|
|
||||||
pthread_kill(id, SIGUSR1);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
pause_time = Libraries::Kernel::Dev::GetClock()->GetUptime();
|
|
||||||
is_guest_threads_paused = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SystemState::ResumeGuestThreads() {
|
|
||||||
std::lock_guard lock{guest_threads_mutex};
|
|
||||||
if (!is_guest_threads_paused) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 delta_time = Libraries::Kernel::Dev::GetClock()->GetUptime() - pause_time;
|
|
||||||
Libraries::Kernel::Dev::GetInitialPtc() += delta_time;
|
|
||||||
for (const auto& id : guest_threads) {
|
|
||||||
#ifdef _WIN32
|
|
||||||
const HANDLE hd = OpenThread(THREAD_SUSPEND_RESUME, FALSE, id);
|
|
||||||
ResumeThread(hd);
|
|
||||||
CloseHandle(hd);
|
|
||||||
#else
|
|
||||||
pthread_kill(id, SIGUSR1);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
is_guest_threads_paused = false;
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
|
||||||
#define WIN32_LEAN_AND_MEAN 1
|
|
||||||
#endif
|
|
||||||
#include <Windows.h>
|
|
||||||
using ThreadID = DWORD;
|
|
||||||
#else
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <signal.h>
|
|
||||||
using ThreadID = pthread_t;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class SystemState {
|
|
||||||
std::mutex guest_threads_mutex{};
|
|
||||||
std::vector<ThreadID> guest_threads{};
|
|
||||||
bool is_guest_threads_paused = false;
|
|
||||||
u64 pause_time{};
|
|
||||||
|
|
||||||
public:
|
|
||||||
void AddCurrentThreadToGuestList();
|
|
||||||
|
|
||||||
void RemoveCurrentThreadFromGuestList();
|
|
||||||
|
|
||||||
void PauseGuestThreads();
|
|
||||||
|
|
||||||
void ResumeGuestThreads();
|
|
||||||
|
|
||||||
inline bool IsGuestThreadsPaused() const {
|
|
||||||
return is_guest_threads_paused;
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -61,7 +61,6 @@ Emulator::Emulator() {
|
||||||
LOG_INFO(Config, "General isNeo: {}", Config::isNeoMode());
|
LOG_INFO(Config, "General isNeo: {}", Config::isNeoMode());
|
||||||
LOG_INFO(Config, "GPU isNullGpu: {}", Config::nullGpu());
|
LOG_INFO(Config, "GPU isNullGpu: {}", Config::nullGpu());
|
||||||
LOG_INFO(Config, "GPU shouldDumpShaders: {}", Config::dumpShaders());
|
LOG_INFO(Config, "GPU shouldDumpShaders: {}", Config::dumpShaders());
|
||||||
LOG_INFO(Config, "GPU shouldDumpPM4: {}", Config::dumpPM4());
|
|
||||||
LOG_INFO(Config, "GPU vblankDivider: {}", Config::vblankDiv());
|
LOG_INFO(Config, "GPU vblankDivider: {}", Config::vblankDiv());
|
||||||
LOG_INFO(Config, "Vulkan gpuId: {}", Config::getGpuId());
|
LOG_INFO(Config, "Vulkan gpuId: {}", Config::getGpuId());
|
||||||
LOG_INFO(Config, "Vulkan vkValidation: {}", Config::vkValidationEnabled());
|
LOG_INFO(Config, "Vulkan vkValidation: {}", Config::vkValidationEnabled());
|
||||||
|
|
|
@ -27,6 +27,20 @@ inline void CentralizeWindow() {
|
||||||
SetNextWindowPos(display_size / 2.0f, ImGuiCond_Always, {0.5f});
|
SetNextWindowPos(display_size / 2.0f, ImGuiCond_Always, {0.5f});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void KeepWindowInside(ImVec2 display_size = GetIO().DisplaySize) {
|
||||||
|
const auto cur_pos = GetWindowPos();
|
||||||
|
if (cur_pos.x < 0.0f || cur_pos.y < 0.0f) {
|
||||||
|
SetWindowPos(ImMax(cur_pos, ImVec2(0.0f, 0.0f)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto cur_size = GetWindowSize();
|
||||||
|
const auto bottom_right = cur_pos + cur_size;
|
||||||
|
if (bottom_right.x > display_size.x || bottom_right.y > display_size.y) {
|
||||||
|
const auto max_pos = display_size - cur_size;
|
||||||
|
SetWindowPos(ImMin(cur_pos, max_pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline void KeepNavHighlight() {
|
inline void KeepNavHighlight() {
|
||||||
GetCurrentContext()->NavDisableHighlight = false;
|
GetCurrentContext()->NavDisableHighlight = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,162 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#include <imgui.h>
|
|
||||||
|
|
||||||
#include "common/config.h"
|
|
||||||
#include "common/singleton.h"
|
|
||||||
#include "common/types.h"
|
|
||||||
#include "core/system.h"
|
|
||||||
#include "imgui_internal.h"
|
|
||||||
#include "video_info.h"
|
|
||||||
|
|
||||||
using namespace ImGui;
|
|
||||||
|
|
||||||
struct FrameInfo {
|
|
||||||
u32 num;
|
|
||||||
float delta;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool show = false;
|
|
||||||
static bool show_advanced = false;
|
|
||||||
|
|
||||||
static auto sysState = Common::Singleton<SystemState>::Instance();
|
|
||||||
static u32 current_frame = 0;
|
|
||||||
|
|
||||||
namespace FrameGraph {
|
|
||||||
|
|
||||||
constexpr float TARGET_FPS = 60.0f;
|
|
||||||
constexpr u32 FRAME_BUFFER_SIZE = 1024;
|
|
||||||
constexpr float BAR_WIDTH_MULT = 1.4f;
|
|
||||||
constexpr float BAR_HEIGHT_MULT = 1.25f;
|
|
||||||
constexpr float FRAME_GRAPH_PADDING_Y = 3.0f;
|
|
||||||
static std::array<FrameInfo, FRAME_BUFFER_SIZE> frame_list;
|
|
||||||
static float frame_graph_height = 50.0f;
|
|
||||||
|
|
||||||
static void Draw() {
|
|
||||||
const auto& ctx = *GImGui;
|
|
||||||
const auto& window = *ctx.CurrentWindow;
|
|
||||||
auto& draw_list = *window.DrawList;
|
|
||||||
|
|
||||||
const float full_width = GetContentRegionAvail().x;
|
|
||||||
// Frame graph - inspired by
|
|
||||||
// https://asawicki.info/news_1758_an_idea_for_visualization_of_frame_times
|
|
||||||
auto pos = GetCursorScreenPos();
|
|
||||||
const ImVec2 size{full_width, frame_graph_height + FRAME_GRAPH_PADDING_Y * 2.0f};
|
|
||||||
ItemSize(size);
|
|
||||||
if (!ItemAdd({pos, pos + size}, GetID("FrameGraph"))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float target_dt = 1.0f / (TARGET_FPS * (float)Config::vblankDiv());
|
|
||||||
float cur_pos_x = pos.x + full_width;
|
|
||||||
pos.y += FRAME_GRAPH_PADDING_Y;
|
|
||||||
const float final_pos_y = pos.y + frame_graph_height;
|
|
||||||
|
|
||||||
draw_list.AddRectFilled({pos.x, pos.y - FRAME_GRAPH_PADDING_Y},
|
|
||||||
{pos.x + full_width, final_pos_y + FRAME_GRAPH_PADDING_Y},
|
|
||||||
IM_COL32(0x33, 0x33, 0x33, 0xFF));
|
|
||||||
draw_list.PushClipRect({pos.x, pos.y}, {pos.x + full_width, final_pos_y}, true);
|
|
||||||
for (u32 i = 0; i < FRAME_BUFFER_SIZE; ++i) {
|
|
||||||
const auto& frame_info = frame_list[(current_frame - i) % FRAME_BUFFER_SIZE];
|
|
||||||
const float dt_factor = target_dt / frame_info.delta;
|
|
||||||
|
|
||||||
const float width = std::ceil(BAR_WIDTH_MULT / dt_factor);
|
|
||||||
const float height =
|
|
||||||
std::min(std::log2(BAR_HEIGHT_MULT / dt_factor) / 3.0f, 1.0f) * frame_graph_height;
|
|
||||||
|
|
||||||
ImU32 color;
|
|
||||||
if (dt_factor >= 0.95f) { // BLUE
|
|
||||||
color = IM_COL32(0x33, 0x33, 0xFF, 0xFF);
|
|
||||||
} else if (dt_factor >= 0.5f) { // GREEN <> YELLOW
|
|
||||||
float t = 1.0f - (dt_factor - 0.5f) * 2.0f;
|
|
||||||
int r = (int)(0xFF * t);
|
|
||||||
color = IM_COL32(r, 0xFF, 0, 0xFF);
|
|
||||||
} else { // YELLOW <> RED
|
|
||||||
float t = dt_factor * 2.0f;
|
|
||||||
int g = (int)(0xFF * t);
|
|
||||||
color = IM_COL32(0xFF, g, 0, 0xFF);
|
|
||||||
}
|
|
||||||
draw_list.AddRectFilled({cur_pos_x - width, final_pos_y - height}, {cur_pos_x, final_pos_y},
|
|
||||||
color);
|
|
||||||
cur_pos_x -= width;
|
|
||||||
if (cur_pos_x < width) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
draw_list.PopClipRect();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace FrameGraph
|
|
||||||
|
|
||||||
static void DrawSimple() {
|
|
||||||
const auto io = GetIO();
|
|
||||||
Text("FPS: %.1f (%.3f ms)", io.Framerate, 1000.0f / io.Framerate);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DrawAdvanced() {
|
|
||||||
const auto& ctx = *GImGui;
|
|
||||||
const auto& io = ctx.IO;
|
|
||||||
const auto& window = *ctx.CurrentWindow;
|
|
||||||
auto& draw_list = *window.DrawList;
|
|
||||||
|
|
||||||
auto isSystemPaused = sysState->IsGuestThreadsPaused();
|
|
||||||
|
|
||||||
static float deltaTime;
|
|
||||||
static float frameRate;
|
|
||||||
|
|
||||||
if (!isSystemPaused) {
|
|
||||||
deltaTime = io.DeltaTime * 1000.0f;
|
|
||||||
frameRate = io.Framerate;
|
|
||||||
}
|
|
||||||
|
|
||||||
Text("Frame time: %.3f ms (%.1f FPS)", deltaTime, frameRate);
|
|
||||||
|
|
||||||
SeparatorText("Frame graph");
|
|
||||||
FrameGraph::Draw();
|
|
||||||
SeparatorText("System debug");
|
|
||||||
BeginDisabled(isSystemPaused);
|
|
||||||
if (Button("Pause")) {
|
|
||||||
sysState->PauseGuestThreads();
|
|
||||||
}
|
|
||||||
EndDisabled();
|
|
||||||
SameLine();
|
|
||||||
BeginDisabled(!isSystemPaused);
|
|
||||||
if (Button("Resume")) {
|
|
||||||
sysState->ResumeGuestThreads();
|
|
||||||
}
|
|
||||||
EndDisabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Layers::VideoInfo::Draw() {
|
|
||||||
const auto io = GetIO();
|
|
||||||
|
|
||||||
if (!sysState->IsGuestThreadsPaused()) {
|
|
||||||
const FrameInfo frame_info{
|
|
||||||
.num = ++current_frame,
|
|
||||||
.delta = io.DeltaTime,
|
|
||||||
};
|
|
||||||
FrameGraph::frame_list[current_frame % FrameGraph::FRAME_BUFFER_SIZE] = frame_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsKeyPressed(ImGuiKey_F10, false)) {
|
|
||||||
const bool changed_ctrl = io.KeyCtrl != show_advanced;
|
|
||||||
show_advanced = io.KeyCtrl;
|
|
||||||
show = changed_ctrl || !show;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (show) {
|
|
||||||
if (show_advanced) {
|
|
||||||
if (Begin("Video Debug Info", &show, 0)) {
|
|
||||||
DrawAdvanced();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (Begin("Video Info", nullptr,
|
|
||||||
ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDecoration |
|
|
||||||
ImGuiWindowFlags_AlwaysAutoResize)) {
|
|
||||||
DrawSimple();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
End();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "imgui/imgui_layer.h"
|
|
||||||
|
|
||||||
namespace Vulkan {
|
|
||||||
class RendererVulkan;
|
|
||||||
}
|
|
||||||
namespace ImGui::Layers {
|
|
||||||
|
|
||||||
class VideoInfo : public Layer {
|
|
||||||
::Vulkan::RendererVulkan* renderer{};
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit VideoInfo(::Vulkan::RendererVulkan* renderer) : renderer(renderer) {}
|
|
||||||
|
|
||||||
void Draw() override;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace ImGui::Layers
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
#include "common/path_util.h"
|
#include "common/path_util.h"
|
||||||
|
#include "core/devtools/layer.h"
|
||||||
#include "imgui/imgui_layer.h"
|
#include "imgui/imgui_layer.h"
|
||||||
#include "imgui_core.h"
|
#include "imgui_core.h"
|
||||||
#include "imgui_impl_sdl3.h"
|
#include "imgui_impl_sdl3.h"
|
||||||
|
@ -74,12 +75,14 @@ void Initialize(const ::Vulkan::Instance& instance, const Frontend::WindowSDL& w
|
||||||
ImFontConfig font_cfg{};
|
ImFontConfig font_cfg{};
|
||||||
font_cfg.OversampleH = 2;
|
font_cfg.OversampleH = 2;
|
||||||
font_cfg.OversampleV = 1;
|
font_cfg.OversampleV = 1;
|
||||||
io.Fonts->AddFontFromMemoryCompressedTTF(imgui_font_notosansjp_regular_compressed_data,
|
io.Fonts->AddFontDefault();
|
||||||
imgui_font_notosansjp_regular_compressed_size, 16.0f,
|
io.FontDefault = io.Fonts->AddFontFromMemoryCompressedTTF(
|
||||||
&font_cfg, ranges.Data);
|
imgui_font_notosansjp_regular_compressed_data,
|
||||||
|
imgui_font_notosansjp_regular_compressed_size, 16.0f, &font_cfg, ranges.Data);
|
||||||
|
|
||||||
StyleColorsDark();
|
StyleColorsDark();
|
||||||
|
|
||||||
|
::Core::Devtools::Layer::SetupSettings();
|
||||||
Sdl::Init(window.GetSdlWindow());
|
Sdl::Init(window.GetSdlWindow());
|
||||||
|
|
||||||
const Vulkan::InitInfo vk_info{
|
const Vulkan::InitInfo vk_info{
|
||||||
|
@ -166,6 +169,8 @@ void NewFrame() {
|
||||||
Sdl::NewFrame();
|
Sdl::NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
DockSpaceOverViewport(0, GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode);
|
||||||
|
|
||||||
for (auto* layer : layers) {
|
for (auto* layer : layers) {
|
||||||
layer->Draw();
|
layer->Draw();
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,9 +174,6 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
|
||||||
|
|
||||||
connect(ui->nullGpuCheckBox, &QCheckBox::stateChanged, this,
|
connect(ui->nullGpuCheckBox, &QCheckBox::stateChanged, this,
|
||||||
[](int val) { Config::setNullGpu(val); });
|
[](int val) { Config::setNullGpu(val); });
|
||||||
|
|
||||||
connect(ui->dumpPM4CheckBox, &QCheckBox::stateChanged, this,
|
|
||||||
[](int val) { Config::setDumpPM4(val); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEBUG TAB
|
// DEBUG TAB
|
||||||
|
@ -215,7 +212,6 @@ SettingsDialog::SettingsDialog(std::span<const QString> physical_devices, QWidge
|
||||||
ui->heightDivider->installEventFilter(this);
|
ui->heightDivider->installEventFilter(this);
|
||||||
ui->dumpShadersCheckBox->installEventFilter(this);
|
ui->dumpShadersCheckBox->installEventFilter(this);
|
||||||
ui->nullGpuCheckBox->installEventFilter(this);
|
ui->nullGpuCheckBox->installEventFilter(this);
|
||||||
ui->dumpPM4CheckBox->installEventFilter(this);
|
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
ui->debugDump->installEventFilter(this);
|
ui->debugDump->installEventFilter(this);
|
||||||
|
@ -238,7 +234,6 @@ void SettingsDialog::LoadValuesFromConfig() {
|
||||||
ui->vblankSpinBox->setValue(Config::vblankDiv());
|
ui->vblankSpinBox->setValue(Config::vblankDiv());
|
||||||
ui->dumpShadersCheckBox->setChecked(Config::dumpShaders());
|
ui->dumpShadersCheckBox->setChecked(Config::dumpShaders());
|
||||||
ui->nullGpuCheckBox->setChecked(Config::nullGpu());
|
ui->nullGpuCheckBox->setChecked(Config::nullGpu());
|
||||||
ui->dumpPM4CheckBox->setChecked(Config::dumpPM4());
|
|
||||||
ui->playBGMCheckBox->setChecked(Config::getPlayBGM());
|
ui->playBGMCheckBox->setChecked(Config::getPlayBGM());
|
||||||
ui->BGMVolumeSlider->setValue((Config::getBGMvolume()));
|
ui->BGMVolumeSlider->setValue((Config::getBGMvolume()));
|
||||||
ui->fullscreenCheckBox->setChecked(Config::isFullscreenMode());
|
ui->fullscreenCheckBox->setChecked(Config::isFullscreenMode());
|
||||||
|
|
|
@ -664,13 +664,6 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QCheckBox" name="dumpPM4CheckBox">
|
|
||||||
<property name="text">
|
|
||||||
<string>Enable PM4 Dumping</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -363,13 +363,16 @@ struct Liverpool {
|
||||||
Stencil8 = 1,
|
Stencil8 = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union ZInfo {
|
||||||
BitField<0, 2, ZFormat> format;
|
BitField<0, 2, ZFormat> format;
|
||||||
BitField<2, 2, u32> num_samples;
|
BitField<2, 2, u32> num_samples;
|
||||||
BitField<13, 3, u32> tile_split;
|
BitField<13, 3, u32> tile_split;
|
||||||
|
BitField<20, 3, u32> tile_mode_index;
|
||||||
|
BitField<23, 4, u32> decompress_on_n_zplanes;
|
||||||
BitField<27, 1, u32> allow_expclear;
|
BitField<27, 1, u32> allow_expclear;
|
||||||
BitField<28, 1, u32> read_size;
|
BitField<28, 1, u32> read_size;
|
||||||
BitField<29, 1, u32> tile_surface_en;
|
BitField<29, 1, u32> tile_surface_en;
|
||||||
|
BitField<30, 1, u32> clear_disallowed;
|
||||||
BitField<31, 1, u32> zrange_precision;
|
BitField<31, 1, u32> zrange_precision;
|
||||||
} z_info;
|
} z_info;
|
||||||
union {
|
union {
|
||||||
|
@ -472,6 +475,8 @@ struct Liverpool {
|
||||||
BitField<13, 1, u32> enable_polygon_offset_para;
|
BitField<13, 1, u32> enable_polygon_offset_para;
|
||||||
BitField<16, 1, u32> enable_window_offset;
|
BitField<16, 1, u32> enable_window_offset;
|
||||||
BitField<19, 1, ProvokingVtxLast> provoking_vtx_last;
|
BitField<19, 1, ProvokingVtxLast> provoking_vtx_last;
|
||||||
|
BitField<20, 1, u32> persp_corr_dis;
|
||||||
|
BitField<21, 1, u32> multi_prim_ib_ena;
|
||||||
|
|
||||||
PolygonMode PolyMode() const {
|
PolygonMode PolyMode() const {
|
||||||
return enable_polygon_mode ? polygon_mode_front.Value() : PolygonMode::Fill;
|
return enable_polygon_mode ? polygon_mode_front.Value() : PolygonMode::Fill;
|
||||||
|
@ -634,6 +639,7 @@ struct Liverpool {
|
||||||
BitField<8, 1, u32> xy_transformed;
|
BitField<8, 1, u32> xy_transformed;
|
||||||
BitField<9, 1, u32> z_transformed;
|
BitField<9, 1, u32> z_transformed;
|
||||||
BitField<10, 1, u32> w_transformed;
|
BitField<10, 1, u32> w_transformed;
|
||||||
|
BitField<11, 1, u32> perfcounter_ref;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ClipUserData {
|
struct ClipUserData {
|
||||||
|
@ -689,6 +695,7 @@ struct Liverpool {
|
||||||
BitField<24, 5, BlendFactor> alpha_dst_factor;
|
BitField<24, 5, BlendFactor> alpha_dst_factor;
|
||||||
BitField<29, 1, u32> separate_alpha_blend;
|
BitField<29, 1, u32> separate_alpha_blend;
|
||||||
BitField<30, 1, u32> enable;
|
BitField<30, 1, u32> enable;
|
||||||
|
BitField<31, 1, u32> disable_rop3;
|
||||||
};
|
};
|
||||||
|
|
||||||
union ColorControl {
|
union ColorControl {
|
||||||
|
@ -697,9 +704,11 @@ struct Liverpool {
|
||||||
Normal = 1u,
|
Normal = 1u,
|
||||||
EliminateFastClear = 2u,
|
EliminateFastClear = 2u,
|
||||||
Resolve = 3u,
|
Resolve = 3u,
|
||||||
|
Err = 4u,
|
||||||
FmaskDecompress = 5u,
|
FmaskDecompress = 5u,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BitField<0, 1, u32> disable_dual_quad;
|
||||||
BitField<3, 1, u32> degamma_enable;
|
BitField<3, 1, u32> degamma_enable;
|
||||||
BitField<4, 3, OperationMode> mode;
|
BitField<4, 3, OperationMode> mode;
|
||||||
BitField<16, 8, u32> rop3;
|
BitField<16, 8, u32> rop3;
|
||||||
|
@ -737,7 +746,7 @@ struct Liverpool {
|
||||||
BitField<0, 11, u32> slice_start;
|
BitField<0, 11, u32> slice_start;
|
||||||
BitField<13, 11, u32> slice_max;
|
BitField<13, 11, u32> slice_max;
|
||||||
} view;
|
} view;
|
||||||
union {
|
union Color0Info {
|
||||||
BitField<0, 2, EndianSwap> endian;
|
BitField<0, 2, EndianSwap> endian;
|
||||||
BitField<2, 5, DataFormat> format;
|
BitField<2, 5, DataFormat> format;
|
||||||
BitField<7, 1, u32> linear_general;
|
BitField<7, 1, u32> linear_general;
|
||||||
|
@ -750,10 +759,17 @@ struct Liverpool {
|
||||||
BitField<17, 1, u32> simple_float;
|
BitField<17, 1, u32> simple_float;
|
||||||
BitField<18, 1, RoundMode> round_mode;
|
BitField<18, 1, RoundMode> round_mode;
|
||||||
BitField<19, 1, u32> cmask_is_linear;
|
BitField<19, 1, u32> cmask_is_linear;
|
||||||
|
BitField<20, 3, u32> blend_opt_dont_rd_dst;
|
||||||
|
BitField<23, 3, u32> blend_opt_discard_pixel;
|
||||||
|
BitField<26, 1, u32> fmask_compression_disable_ci;
|
||||||
|
BitField<27, 1, u32> fmask_compress_1frag_only;
|
||||||
|
BitField<28, 1, u32> dcc_enable;
|
||||||
|
BitField<29, 1, u32> cmask_addr_type;
|
||||||
} info;
|
} info;
|
||||||
union {
|
union Color0Attrib {
|
||||||
BitField<0, 5, TilingMode> tile_mode_index;
|
BitField<0, 5, TilingMode> tile_mode_index;
|
||||||
BitField<5, 5, u32> fmask_tile_mode_index;
|
BitField<5, 5, u32> fmask_tile_mode_index;
|
||||||
|
BitField<10, 2, u32> fmask_bank_height;
|
||||||
BitField<12, 3, u32> num_samples_log2;
|
BitField<12, 3, u32> num_samples_log2;
|
||||||
BitField<15, 2, u32> num_fragments_log2;
|
BitField<15, 2, u32> num_fragments_log2;
|
||||||
BitField<17, 1, u32> force_dst_alpha_1;
|
BitField<17, 1, u32> force_dst_alpha_1;
|
||||||
|
@ -886,8 +902,14 @@ struct Liverpool {
|
||||||
u32 raw;
|
u32 raw;
|
||||||
BitField<0, 1, u32> depth_clear_enable;
|
BitField<0, 1, u32> depth_clear_enable;
|
||||||
BitField<1, 1, u32> stencil_clear_enable;
|
BitField<1, 1, u32> stencil_clear_enable;
|
||||||
|
BitField<2, 1, u32> depth_copy;
|
||||||
|
BitField<3, 1, u32> stencil_copy;
|
||||||
|
BitField<4, 1, u32> resummarize_enable;
|
||||||
BitField<5, 1, u32> stencil_compress_disable;
|
BitField<5, 1, u32> stencil_compress_disable;
|
||||||
BitField<6, 1, u32> depth_compress_disable;
|
BitField<6, 1, u32> depth_compress_disable;
|
||||||
|
BitField<7, 1, u32> copy_centroid;
|
||||||
|
BitField<8, 1, u32> copy_sample;
|
||||||
|
BitField<9, 1, u32> decompress_enable;
|
||||||
};
|
};
|
||||||
|
|
||||||
union DepthView {
|
union DepthView {
|
||||||
|
@ -940,6 +962,22 @@ struct Liverpool {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
union Eqaa {
|
||||||
|
u32 raw;
|
||||||
|
BitField<0, 1, u32> max_anchor_samples;
|
||||||
|
BitField<4, 3, u32> ps_iter_samples;
|
||||||
|
BitField<8, 3, u32> mask_export_num_samples;
|
||||||
|
BitField<12, 3, u32> alpha_to_mask_num_samples;
|
||||||
|
BitField<16, 1, u32> high_quality_intersections;
|
||||||
|
BitField<17, 1, u32> incoherent_eqaa_reads;
|
||||||
|
BitField<18, 1, u32> interpolate_comp_z;
|
||||||
|
BitField<19, 1, u32> interpolate_src_z;
|
||||||
|
BitField<20, 1, u32> static_anchor_associations;
|
||||||
|
BitField<21, 1, u32> alpha_to_mask_eqaa_disable;
|
||||||
|
BitField<24, 3, u32> overrasterization_amount;
|
||||||
|
BitField<27, 1, u32> enable_postz_overrasterization;
|
||||||
|
};
|
||||||
|
|
||||||
union Regs {
|
union Regs {
|
||||||
struct {
|
struct {
|
||||||
INSERT_PADDING_WORDS(0x2C08);
|
INSERT_PADDING_WORDS(0x2C08);
|
||||||
|
|
|
@ -36,6 +36,8 @@ union PM4Type0Header {
|
||||||
};
|
};
|
||||||
|
|
||||||
union PM4Type3Header {
|
union PM4Type3Header {
|
||||||
|
static constexpr u32 TYPE = 3;
|
||||||
|
|
||||||
constexpr PM4Type3Header(PM4ItOpcode code, u32 num_words_min_one,
|
constexpr PM4Type3Header(PM4ItOpcode code, u32 num_words_min_one,
|
||||||
PM4ShaderType stype = PM4ShaderType::ShaderGraphics,
|
PM4ShaderType stype = PM4ShaderType::ShaderGraphics,
|
||||||
PM4Predicate pred = PM4Predicate::PredDisable) {
|
PM4Predicate pred = PM4Predicate::PredDisable) {
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
|
|
||||||
#include <vk_mem_alloc.h>
|
#include <vk_mem_alloc.h>
|
||||||
|
|
||||||
|
#include "core/debug_state.h"
|
||||||
|
#include "core/devtools/layer.h"
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
bool CanBlitToSwapchain(const vk::PhysicalDevice physical_device, vk::Format format) {
|
bool CanBlitToSwapchain(const vk::PhysicalDevice physical_device, vk::Format format) {
|
||||||
|
@ -96,7 +99,7 @@ RendererVulkan::RendererVulkan(Frontend::WindowSDL& window_, AmdGpu::Liverpool*
|
||||||
draw_scheduler{instance}, present_scheduler{instance}, flip_scheduler{instance},
|
draw_scheduler{instance}, present_scheduler{instance}, flip_scheduler{instance},
|
||||||
swapchain{instance, window},
|
swapchain{instance, window},
|
||||||
rasterizer{std::make_unique<Rasterizer>(instance, draw_scheduler, liverpool)},
|
rasterizer{std::make_unique<Rasterizer>(instance, draw_scheduler, liverpool)},
|
||||||
texture_cache{rasterizer->GetTextureCache()}, video_info_ui{this} {
|
texture_cache{rasterizer->GetTextureCache()} {
|
||||||
const u32 num_images = swapchain.GetImageCount();
|
const u32 num_images = swapchain.GetImageCount();
|
||||||
const vk::Device device = instance.GetDevice();
|
const vk::Device device = instance.GetDevice();
|
||||||
|
|
||||||
|
@ -114,11 +117,11 @@ RendererVulkan::RendererVulkan(Frontend::WindowSDL& window_, AmdGpu::Liverpool*
|
||||||
|
|
||||||
// Setup ImGui
|
// Setup ImGui
|
||||||
ImGui::Core::Initialize(instance, window, num_images, swapchain.GetSurfaceFormat().format);
|
ImGui::Core::Initialize(instance, window, num_images, swapchain.GetSurfaceFormat().format);
|
||||||
ImGui::Layer::AddLayer(&video_info_ui);
|
ImGui::Layer::AddLayer(Common::Singleton<Core::Devtools::Layer>::Instance());
|
||||||
}
|
}
|
||||||
|
|
||||||
RendererVulkan::~RendererVulkan() {
|
RendererVulkan::~RendererVulkan() {
|
||||||
ImGui::Layer::RemoveLayer(&video_info_ui);
|
ImGui::Layer::RemoveLayer(Common::Singleton<Core::Devtools::Layer>::Instance());
|
||||||
draw_scheduler.Finish();
|
draw_scheduler.Finish();
|
||||||
const vk::Device device = instance.GetDevice();
|
const vk::Device device = instance.GetDevice();
|
||||||
for (auto& frame : present_frames) {
|
for (auto& frame : present_frames) {
|
||||||
|
@ -416,6 +419,8 @@ void RendererVulkan::Present(Frame* frame) {
|
||||||
std::scoped_lock fl{free_mutex};
|
std::scoped_lock fl{free_mutex};
|
||||||
free_queue.push(frame);
|
free_queue.push(frame);
|
||||||
free_cv.notify_one();
|
free_cv.notify_one();
|
||||||
|
|
||||||
|
DebugState.IncFlipFrameNum();
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame* RendererVulkan::GetRenderFrame() {
|
Frame* RendererVulkan::GetRenderFrame() {
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
|
||||||
#include "imgui/layer/video_info.h"
|
|
||||||
#include "video_core/amdgpu/liverpool.h"
|
#include "video_core/amdgpu/liverpool.h"
|
||||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||||
|
@ -105,8 +104,6 @@ private:
|
||||||
std::condition_variable_any frame_cv;
|
std::condition_variable_any frame_cv;
|
||||||
std::optional<VideoCore::Image> splash_img;
|
std::optional<VideoCore::Image> splash_img;
|
||||||
std::vector<VAddr> vo_buffers_addr;
|
std::vector<VAddr> vo_buffers_addr;
|
||||||
|
|
||||||
ImGui::Layers::VideoInfo video_info_ui;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue