2024-10-03 20:43:23 +00:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <atomic>
|
|
|
|
#include <mutex>
|
2024-10-13 12:02:22 +00:00
|
|
|
#include <shared_mutex>
|
|
|
|
#include <unordered_map>
|
2024-10-03 20:43:23 +00:00
|
|
|
#include <vector>
|
|
|
|
#include <queue>
|
|
|
|
|
|
|
|
#include "common/types.h"
|
2024-10-13 12:02:22 +00:00
|
|
|
#include "video_core/amdgpu/liverpool.h"
|
2024-12-09 20:11:11 +00:00
|
|
|
#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
|
2024-10-03 20:43:23 +00:00
|
|
|
|
|
|
|
#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;
|
2024-12-01 18:34:29 +00:00
|
|
|
class ShaderList;
|
|
|
|
} // namespace Widget
|
2024-10-03 20:43:23 +00:00
|
|
|
} // namespace Core::Devtools
|
|
|
|
|
|
|
|
namespace DebugStateType {
|
|
|
|
|
|
|
|
enum class QueueType {
|
2024-10-16 10:12:46 +00:00
|
|
|
dcb = 0,
|
|
|
|
ccb = 1,
|
|
|
|
acb = 2,
|
2024-10-03 20:43:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct QueueDump {
|
|
|
|
QueueType type;
|
|
|
|
u32 submit_num;
|
|
|
|
u32 num2; // acb: queue_num; else: buffer_in_submit
|
|
|
|
std::vector<u32> data;
|
2024-10-13 12:02:22 +00:00
|
|
|
uintptr_t base_addr;
|
|
|
|
};
|
|
|
|
|
2024-12-01 18:34:29 +00:00
|
|
|
struct PipelineShaderProgramDump {
|
2024-10-13 12:02:22 +00:00
|
|
|
Vulkan::Liverpool::ShaderProgram user_data{};
|
|
|
|
std::vector<u32> code{};
|
|
|
|
};
|
|
|
|
|
2024-12-01 18:34:29 +00:00
|
|
|
struct PipelineComputerProgramDump {
|
2024-10-16 10:12:46 +00:00
|
|
|
Vulkan::Liverpool::ComputeProgram cs_program{};
|
|
|
|
std::vector<u32> code{};
|
|
|
|
};
|
|
|
|
|
2024-10-13 12:02:22 +00:00
|
|
|
struct RegDump {
|
2024-10-16 10:12:46 +00:00
|
|
|
bool is_compute{false};
|
2024-10-13 12:02:22 +00:00
|
|
|
static constexpr size_t MaxShaderStages = 5;
|
|
|
|
Vulkan::Liverpool::Regs regs{};
|
2024-12-01 18:34:29 +00:00
|
|
|
std::array<PipelineShaderProgramDump, MaxShaderStages> stages{};
|
|
|
|
PipelineComputerProgramDump cs_data{};
|
2024-10-03 20:43:23 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct FrameDump {
|
2024-10-16 10:12:46 +00:00
|
|
|
u32 frame_id;
|
2024-10-03 20:43:23 +00:00
|
|
|
std::vector<QueueDump> queues;
|
2024-10-13 12:02:22 +00:00
|
|
|
std::unordered_map<uintptr_t, RegDump> regs; // address -> reg dump
|
2024-10-03 20:43:23 +00:00
|
|
|
};
|
|
|
|
|
2024-12-01 18:34:29 +00:00
|
|
|
struct ShaderDump {
|
|
|
|
std::string name;
|
2024-12-09 20:11:11 +00:00
|
|
|
vk::ShaderModule module;
|
|
|
|
|
2024-12-01 18:34:29 +00:00
|
|
|
std::vector<u32> spv;
|
2024-12-09 20:11:11 +00:00
|
|
|
std::vector<u32> isa;
|
|
|
|
|
|
|
|
std::vector<u32> patch_spv;
|
|
|
|
std::string patch_source{};
|
2024-12-01 18:34:29 +00:00
|
|
|
|
2024-12-09 20:11:11 +00:00
|
|
|
bool loaded_data = false;
|
|
|
|
bool is_patched = false;
|
2024-12-01 18:34:29 +00:00
|
|
|
std::string cache_spv_disasm{};
|
2024-12-09 20:11:11 +00:00
|
|
|
std::string cache_isa_disasm{};
|
|
|
|
std::string cache_patch_disasm{};
|
2024-12-01 18:34:29 +00:00
|
|
|
|
2024-12-09 20:11:11 +00:00
|
|
|
ShaderDump(std::string name, vk::ShaderModule module, std::vector<u32> spv,
|
|
|
|
std::vector<u32> isa, std::vector<u32> patch_spv, bool is_patched)
|
|
|
|
: name(std::move(name)), module(module), spv(std::move(spv)), isa(std::move(isa)),
|
|
|
|
patch_spv(std::move(patch_spv)), is_patched(is_patched) {}
|
2024-12-01 18:34:29 +00:00
|
|
|
|
|
|
|
ShaderDump(const ShaderDump& other) = delete;
|
|
|
|
ShaderDump(ShaderDump&& other) noexcept
|
2024-12-09 20:11:11 +00:00
|
|
|
: name{std::move(other.name)}, module{std::move(other.module)}, spv{std::move(other.spv)},
|
|
|
|
isa{std::move(other.isa)}, patch_spv{std::move(other.patch_spv)},
|
|
|
|
patch_source{std::move(other.patch_source)},
|
|
|
|
cache_spv_disasm{std::move(other.cache_spv_disasm)},
|
|
|
|
cache_isa_disasm{std::move(other.cache_isa_disasm)},
|
|
|
|
cache_patch_disasm{std::move(other.cache_patch_disasm)} {}
|
2024-12-01 18:34:29 +00:00
|
|
|
ShaderDump& operator=(const ShaderDump& other) = delete;
|
|
|
|
ShaderDump& operator=(ShaderDump&& other) noexcept {
|
|
|
|
if (this == &other)
|
|
|
|
return *this;
|
|
|
|
name = std::move(other.name);
|
2024-12-09 20:11:11 +00:00
|
|
|
module = std::move(other.module);
|
2024-12-01 18:34:29 +00:00
|
|
|
spv = std::move(other.spv);
|
2024-12-09 20:11:11 +00:00
|
|
|
isa = std::move(other.isa);
|
|
|
|
patch_spv = std::move(other.patch_spv);
|
|
|
|
patch_source = std::move(other.patch_source);
|
2024-12-01 18:34:29 +00:00
|
|
|
cache_spv_disasm = std::move(other.cache_spv_disasm);
|
2024-12-09 20:11:11 +00:00
|
|
|
cache_isa_disasm = std::move(other.cache_isa_disasm);
|
|
|
|
cache_patch_disasm = std::move(other.cache_patch_disasm);
|
2024-12-01 18:34:29 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-10-03 20:43:23 +00:00
|
|
|
class DebugStateImpl {
|
|
|
|
friend class Core::Devtools::Layer;
|
|
|
|
friend class Core::Devtools::Widget::FrameGraph;
|
2024-12-01 18:34:29 +00:00
|
|
|
friend class Core::Devtools::Widget::ShaderList;
|
|
|
|
|
|
|
|
std::queue<std::string> debug_message_popup;
|
2024-10-03 20:43:23 +00:00
|
|
|
|
|
|
|
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;
|
2024-10-13 12:02:22 +00:00
|
|
|
std::unordered_map<size_t, FrameDump*> waiting_reg_dumps;
|
|
|
|
std::unordered_map<size_t, std::string> waiting_reg_dumps_dbg;
|
2024-10-03 20:43:23 +00:00
|
|
|
bool waiting_submit_pause = false;
|
|
|
|
bool should_show_frame_dump = false;
|
|
|
|
|
2024-10-13 12:02:22 +00:00
|
|
|
std::shared_mutex frame_dump_list_mutex;
|
2024-10-03 20:43:23 +00:00
|
|
|
std::vector<FrameDump> frame_dump_list{};
|
|
|
|
|
2024-12-01 18:34:29 +00:00
|
|
|
std::vector<ShaderDump> shader_dump_list{};
|
2024-10-03 20:43:23 +00:00
|
|
|
|
|
|
|
public:
|
2024-10-13 12:02:22 +00:00
|
|
|
void ShowDebugMessage(std::string message) {
|
|
|
|
if (message.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
debug_message_popup.push(std::move(message));
|
|
|
|
}
|
|
|
|
|
2024-10-03 20:43:23 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-10-13 12:02:22 +00:00
|
|
|
bool DumpingCurrentReg() {
|
|
|
|
std::shared_lock lock{frame_dump_list_mutex};
|
|
|
|
return !waiting_reg_dumps.empty();
|
|
|
|
}
|
|
|
|
|
2024-10-03 20:43:23 +00:00
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
2024-10-13 12:02:22 +00:00
|
|
|
void PushQueueDump(QueueDump dump);
|
2024-10-03 20:43:23 +00:00
|
|
|
|
2024-10-13 12:02:22 +00:00
|
|
|
void PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
2024-10-16 10:12:46 +00:00
|
|
|
const AmdGpu::Liverpool::Regs& regs, bool is_compute = false);
|
2024-12-01 18:34:29 +00:00
|
|
|
|
2024-12-09 20:11:11 +00:00
|
|
|
void CollectShader(const std::string& name, vk::ShaderModule module, std::span<const u32> spv,
|
|
|
|
std::span<const u32> raw_code, std::span<const u32> patch_spv,
|
|
|
|
bool is_patched);
|
2024-10-03 20:43:23 +00:00
|
|
|
};
|
|
|
|
} // namespace DebugStateType
|
|
|
|
|
|
|
|
extern DebugStateType::DebugStateImpl& DebugState;
|