mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-04 16:32:39 +00:00
devtools: pm4 - show program disassembly
This commit is contained in:
parent
46018530e8
commit
cd10d1c9ab
@ -346,6 +346,8 @@ set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
|
|||||||
|
|
||||||
set(DEV_TOOLS src/core/devtools/layer.cpp
|
set(DEV_TOOLS src/core/devtools/layer.cpp
|
||||||
src/core/devtools/layer.h
|
src/core/devtools/layer.h
|
||||||
|
src/core/devtools/options.cpp
|
||||||
|
src/core/devtools/options.h
|
||||||
src/core/devtools/gcn/gcn_context_regs.cpp
|
src/core/devtools/gcn/gcn_context_regs.cpp
|
||||||
src/core/devtools/gcn/gcn_op_names.cpp
|
src/core/devtools/gcn/gcn_op_names.cpp
|
||||||
src/core/devtools/gcn/gcn_shader_regs.cpp
|
src/core/devtools/gcn/gcn_shader_regs.cpp
|
||||||
@ -358,6 +360,8 @@ set(DEV_TOOLS src/core/devtools/layer.cpp
|
|||||||
src/core/devtools/widget/imgui_memory_editor.h
|
src/core/devtools/widget/imgui_memory_editor.h
|
||||||
src/core/devtools/widget/reg_view.cpp
|
src/core/devtools/widget/reg_view.cpp
|
||||||
src/core/devtools/widget/reg_view.h
|
src/core/devtools/widget/reg_view.h
|
||||||
|
src/core/devtools/widget/text_editor.cpp
|
||||||
|
src/core/devtools/widget/text_editor.h
|
||||||
src/core/devtools/widget/types.h
|
src/core/devtools/widget/types.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -106,14 +106,57 @@ void DebugStateImpl::RequestFrameDump(s32 count) {
|
|||||||
void DebugStateImpl::PushQueueDump(QueueDump dump) {
|
void DebugStateImpl::PushQueueDump(QueueDump dump) {
|
||||||
ASSERT(DumpingCurrentFrame());
|
ASSERT(DumpingCurrentFrame());
|
||||||
std::unique_lock lock{frame_dump_list_mutex};
|
std::unique_lock lock{frame_dump_list_mutex};
|
||||||
GetFrameDump().queues.push_back(std::move(dump));
|
auto& frame = GetFrameDump();
|
||||||
|
{ // Find draw calls
|
||||||
|
auto data = std::span{dump.data};
|
||||||
|
auto initial_data = data.data();
|
||||||
|
while (!data.empty()) {
|
||||||
|
const auto* header = reinterpret_cast<const AmdGpu::PM4Type3Header*>(data.data());
|
||||||
|
const auto type = header->type;
|
||||||
|
if (type == 2) {
|
||||||
|
data = data.subspan(1);
|
||||||
|
} else if (type != 3) {
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
const AmdGpu::PM4ItOpcode opcode = header->opcode;
|
||||||
|
switch (opcode) {
|
||||||
|
case AmdGpu::PM4ItOpcode::DrawIndex2:
|
||||||
|
case AmdGpu::PM4ItOpcode::DrawIndexOffset2:
|
||||||
|
case AmdGpu::PM4ItOpcode::DrawIndexAuto:
|
||||||
|
case AmdGpu::PM4ItOpcode::DrawIndirect:
|
||||||
|
case AmdGpu::PM4ItOpcode::DrawIndexIndirect:
|
||||||
|
case AmdGpu::PM4ItOpcode::DispatchDirect:
|
||||||
|
case AmdGpu::PM4ItOpcode::DispatchIndirect: {
|
||||||
|
const auto offset =
|
||||||
|
reinterpret_cast<uintptr_t>(header) - reinterpret_cast<uintptr_t>(initial_data);
|
||||||
|
const auto addr = dump.base_addr + offset;
|
||||||
|
waiting_reg_dumps.emplace(addr, &frame);
|
||||||
|
waiting_reg_dumps_dbg.emplace(
|
||||||
|
addr,
|
||||||
|
fmt::format("#{} h({}) queue {} {} {}",
|
||||||
|
frame_dump_list.size() - gnm_frame_dump_request_count, addr,
|
||||||
|
magic_enum::enum_name(dump.type), dump.submit_num, dump.num2));
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
data = data.subspan(header->NumWords() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frame.queues.push_back(std::move(dump));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DebugStateImpl::PushRegsDump(uintptr_t base_addr, const AmdGpu::Liverpool::Regs& regs) {
|
void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||||
ASSERT(DumpingCurrentReg());
|
const AmdGpu::Liverpool::Regs& regs) {
|
||||||
std::unique_lock lock{frame_dump_list_mutex};
|
std::scoped_lock lock{frame_dump_list_mutex};
|
||||||
auto& dump =
|
const auto it = waiting_reg_dumps.find(header_addr);
|
||||||
frame_dump_list[frame_dump_list.size() - liverpool_dump_request_count].regs[base_addr];
|
if (it == waiting_reg_dumps.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto& frame = *it->second;
|
||||||
|
waiting_reg_dumps.erase(it);
|
||||||
|
waiting_reg_dumps_dbg.erase(waiting_reg_dumps_dbg.find(header_addr));
|
||||||
|
auto& dump = frame.regs[header_addr - base_addr];
|
||||||
dump.regs = regs;
|
dump.regs = regs;
|
||||||
for (int i = 0; i < RegDump::MaxShaderStages; i++) {
|
for (int i = 0; i < RegDump::MaxShaderStages; i++) {
|
||||||
if (regs.stage_enable.IsStageEnabled(i)) {
|
if (regs.stage_enable.IsStageEnabled(i)) {
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <shared_mutex>
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
@ -76,10 +78,12 @@ class DebugStateImpl {
|
|||||||
std::atomic_int32_t gnm_frame_count = 0;
|
std::atomic_int32_t gnm_frame_count = 0;
|
||||||
|
|
||||||
s32 gnm_frame_dump_request_count = -1;
|
s32 gnm_frame_dump_request_count = -1;
|
||||||
|
std::unordered_map<size_t, FrameDump*> waiting_reg_dumps;
|
||||||
|
std::unordered_map<size_t, std::string> waiting_reg_dumps_dbg;
|
||||||
bool waiting_submit_pause = false;
|
bool waiting_submit_pause = false;
|
||||||
bool should_show_frame_dump = false;
|
bool should_show_frame_dump = false;
|
||||||
|
|
||||||
std::mutex frame_dump_list_mutex;
|
std::shared_mutex frame_dump_list_mutex;
|
||||||
std::vector<FrameDump> frame_dump_list{};
|
std::vector<FrameDump> frame_dump_list{};
|
||||||
|
|
||||||
std::queue<std::string> debug_message_popup;
|
std::queue<std::string> debug_message_popup;
|
||||||
@ -121,6 +125,11 @@ public:
|
|||||||
return gnm_frame_dump_request_count > 0;
|
return gnm_frame_dump_request_count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DumpingCurrentReg() {
|
||||||
|
std::shared_lock lock{frame_dump_list_mutex};
|
||||||
|
return !waiting_reg_dumps.empty();
|
||||||
|
}
|
||||||
|
|
||||||
bool ShouldPauseInSubmit() const {
|
bool ShouldPauseInSubmit() const {
|
||||||
return waiting_submit_pause && gnm_frame_dump_request_count == 0;
|
return waiting_submit_pause && gnm_frame_dump_request_count == 0;
|
||||||
}
|
}
|
||||||
@ -133,7 +142,8 @@ public:
|
|||||||
|
|
||||||
void PushQueueDump(QueueDump dump);
|
void PushQueueDump(QueueDump dump);
|
||||||
|
|
||||||
void PushRegsDump(uintptr_t base_addr, const AmdGpu::Liverpool::Regs& regs);
|
void PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||||
|
const AmdGpu::Liverpool::Regs& regs);
|
||||||
};
|
};
|
||||||
} // namespace DebugStateType
|
} // namespace DebugStateType
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "imgui/imgui_std.h"
|
#include "imgui/imgui_std.h"
|
||||||
#include "imgui_internal.h"
|
#include "imgui_internal.h"
|
||||||
#include "layer.h"
|
#include "layer.h"
|
||||||
|
#include "options.h"
|
||||||
#include "widget/frame_dump.h"
|
#include "widget/frame_dump.h"
|
||||||
#include "widget/frame_graph.h"
|
#include "widget/frame_graph.h"
|
||||||
|
|
||||||
@ -18,10 +19,9 @@ using namespace Core::Devtools;
|
|||||||
using L = Core::Devtools::Layer;
|
using L = Core::Devtools::Layer;
|
||||||
|
|
||||||
static bool show_simple_fps = false;
|
static bool show_simple_fps = false;
|
||||||
|
|
||||||
static float fps_scale = 1.0f;
|
static float fps_scale = 1.0f;
|
||||||
|
|
||||||
static bool show_advanced_debug = false;
|
static bool show_advanced_debug = false;
|
||||||
|
|
||||||
static int dump_frame_count = 1;
|
static int dump_frame_count = 1;
|
||||||
|
|
||||||
static Widget::FrameGraph frame_graph;
|
static Widget::FrameGraph frame_graph;
|
||||||
@ -29,12 +29,16 @@ static std::vector<Widget::FrameDumpViewer> frame_viewers;
|
|||||||
|
|
||||||
static float debug_popup_timing = 3.0f;
|
static float debug_popup_timing = 3.0f;
|
||||||
|
|
||||||
|
static bool just_opened_options = false;
|
||||||
|
|
||||||
void L::DrawMenuBar() {
|
void L::DrawMenuBar() {
|
||||||
const auto& ctx = *GImGui;
|
const auto& ctx = *GImGui;
|
||||||
const auto& io = ctx.IO;
|
const auto& io = ctx.IO;
|
||||||
|
|
||||||
auto isSystemPaused = DebugState.IsGuestThreadsPaused();
|
auto isSystemPaused = DebugState.IsGuestThreadsPaused();
|
||||||
|
|
||||||
|
bool open_popup_options = false;
|
||||||
|
|
||||||
if (BeginMainMenuBar()) {
|
if (BeginMainMenuBar()) {
|
||||||
if (BeginMenu("Options")) {
|
if (BeginMenu("Options")) {
|
||||||
if (MenuItemEx("Emulator Paused", nullptr, nullptr, isSystemPaused)) {
|
if (MenuItemEx("Emulator Paused", nullptr, nullptr, isSystemPaused)) {
|
||||||
@ -55,6 +59,7 @@ void L::DrawMenuBar() {
|
|||||||
}
|
}
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
|
open_popup_options = MenuItem("Options");
|
||||||
ImGui::EndMenu();
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
EndMainMenuBar();
|
EndMainMenuBar();
|
||||||
@ -74,6 +79,11 @@ void L::DrawMenuBar() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (open_popup_options) {
|
||||||
|
OpenPopup("GPU Tools Options");
|
||||||
|
just_opened_options = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void L::DrawAdvanced() {
|
void L::DrawAdvanced() {
|
||||||
@ -91,7 +101,7 @@ void L::DrawAdvanced() {
|
|||||||
->AddText({10.0f, io.DisplaySize.y - 40.0f}, IM_COL32_WHITE, "Emulator paused");
|
->AddText({10.0f, io.DisplaySize.y - 40.0f}, IM_COL32_WHITE, "Emulator paused");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DebugState.should_show_frame_dump) {
|
if (DebugState.should_show_frame_dump && DebugState.waiting_reg_dumps.empty()) {
|
||||||
DebugState.should_show_frame_dump = false;
|
DebugState.should_show_frame_dump = false;
|
||||||
std::unique_lock lock{DebugState.frame_dump_list_mutex};
|
std::unique_lock lock{DebugState.frame_dump_list_mutex};
|
||||||
while (!DebugState.frame_dump_list.empty()) {
|
while (!DebugState.frame_dump_list.empty()) {
|
||||||
@ -133,6 +143,30 @@ void L::DrawAdvanced() {
|
|||||||
debug_popup_timing = 3.0f;
|
debug_popup_timing = 3.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool close_popup_options = true;
|
||||||
|
if (BeginPopupModal("GPU Tools Options", &close_popup_options,
|
||||||
|
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings)) {
|
||||||
|
static char disassembly_cli[512];
|
||||||
|
|
||||||
|
if (just_opened_options) {
|
||||||
|
just_opened_options = false;
|
||||||
|
auto s = Options.disassembly_cli.copy(disassembly_cli, sizeof(disassembly_cli) - 1);
|
||||||
|
disassembly_cli[s] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
InputText("Shader disassembler: ", disassembly_cli, sizeof(disassembly_cli));
|
||||||
|
if (IsItemHovered()) {
|
||||||
|
SetTooltip(R"(Command to disassemble shaders. Example "dis.exe" --raw "{src}")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Button("Save")) {
|
||||||
|
Options.disassembly_cli = disassembly_cli;
|
||||||
|
SaveIniSettingsToDisk(io.IniFilename);
|
||||||
|
CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
EndPopup();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void L::DrawSimple() {
|
void L::DrawSimple() {
|
||||||
@ -179,6 +213,10 @@ void L::SetupSettings() {
|
|||||||
std::is_same_v<decltype(&Widget::CmdListViewer::LoadConfig), SettingLoader>);
|
std::is_same_v<decltype(&Widget::CmdListViewer::LoadConfig), SettingLoader>);
|
||||||
return (void*)&Widget::CmdListViewer::LoadConfig;
|
return (void*)&Widget::CmdListViewer::LoadConfig;
|
||||||
}
|
}
|
||||||
|
if (std::string_view("Options") == name) {
|
||||||
|
static_assert(std::is_same_v<decltype(&LoadOptionsConfig), SettingLoader>);
|
||||||
|
return (void*)&LoadOptionsConfig;
|
||||||
|
}
|
||||||
return (void*)nullptr;
|
return (void*)nullptr;
|
||||||
};
|
};
|
||||||
handler.ReadLineFn = [](ImGuiContext*, ImGuiSettingsHandler*, void* handle, const char* line) {
|
handler.ReadLineFn = [](ImGuiContext*, ImGuiSettingsHandler*, void* handle, const char* line) {
|
||||||
@ -196,6 +234,9 @@ void L::SetupSettings() {
|
|||||||
buf->appendf("[%s][CmdList]\n", handler->TypeName);
|
buf->appendf("[%s][CmdList]\n", handler->TypeName);
|
||||||
Widget::CmdListViewer::SerializeConfig(buf);
|
Widget::CmdListViewer::SerializeConfig(buf);
|
||||||
buf->append("\n");
|
buf->append("\n");
|
||||||
|
buf->appendf("[%s][Options]\n", handler->TypeName);
|
||||||
|
SerializeOptionsConfig(buf);
|
||||||
|
buf->append("\n");
|
||||||
};
|
};
|
||||||
AddSettingsHandler(&handler);
|
AddSettingsHandler(&handler);
|
||||||
|
|
||||||
|
24
src/core/devtools/options.cpp
Normal file
24
src/core/devtools/options.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include "options.h"
|
||||||
|
|
||||||
|
namespace Core::Devtools {
|
||||||
|
|
||||||
|
TOptions Options;
|
||||||
|
|
||||||
|
void LoadOptionsConfig(const char* line) {
|
||||||
|
char str[512];
|
||||||
|
if (sscanf(line, "disassembly_cli=%511[^\n]", str) == 1) {
|
||||||
|
Options.disassembly_cli = str;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerializeOptionsConfig(ImGuiTextBuffer* buf) {
|
||||||
|
buf->appendf("disassembly_cli=%s\n", Options.disassembly_cli.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Core::Devtools
|
21
src/core/devtools/options.h
Normal file
21
src/core/devtools/options.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
struct ImGuiTextBuffer;
|
||||||
|
|
||||||
|
namespace Core::Devtools {
|
||||||
|
|
||||||
|
struct TOptions {
|
||||||
|
std::string disassembly_cli;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern TOptions Options;
|
||||||
|
|
||||||
|
void LoadOptionsConfig(const char* line);
|
||||||
|
void SerializeOptionsConfig(ImGuiTextBuffer* buf);
|
||||||
|
|
||||||
|
} // namespace Core::Devtools
|
@ -1246,7 +1246,7 @@ void CmdListViewer::Draw() {
|
|||||||
if (group_batches) {
|
if (group_batches) {
|
||||||
if (IsItemToggledOpen()) {
|
if (IsItemToggledOpen()) {
|
||||||
if (parent->frame_dump.regs.contains(batch.command_addr)) {
|
if (parent->frame_dump.regs.contains(batch.command_addr)) {
|
||||||
batch_view.data = parent->frame_dump.regs.at(batch.command_addr);
|
batch_view.SetData(parent->frame_dump.regs.at(batch.command_addr));
|
||||||
batch_view.open = true;
|
batch_view.open = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1364,7 +1364,8 @@ void CmdListViewer::Draw() {
|
|||||||
cmdb_view.CalcSizes(s, cmdb_size, cmdb_addr);
|
cmdb_view.CalcSizes(s, cmdb_size, cmdb_addr);
|
||||||
SetNextWindowSize({s.WindowWidth, s.WindowWidth * 0.6f}, ImGuiCond_FirstUseEver);
|
SetNextWindowSize({s.WindowWidth, s.WindowWidth * 0.6f}, ImGuiCond_FirstUseEver);
|
||||||
SetNextWindowSizeConstraints({0.0f}, {s.WindowWidth, FLT_MAX});
|
SetNextWindowSizeConstraints({0.0f}, {s.WindowWidth, FLT_MAX});
|
||||||
if (Begin(cmdb_view_name.c_str(), &cmdb_view.Open, ImGuiWindowFlags_NoScrollbar)) {
|
if (Begin(cmdb_view_name.c_str(), &cmdb_view.Open,
|
||||||
|
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings)) {
|
||||||
cmdb_view.DrawContents((void*)cmdb_addr, cmdb_size, base_addr);
|
cmdb_view.DrawContents((void*)cmdb_addr, cmdb_size, base_addr);
|
||||||
if (cmdb_view.ContentsWidthChanged) {
|
if (cmdb_view.ContentsWidthChanged) {
|
||||||
cmdb_view.CalcSizes(s, cmdb_size, cmdb_addr);
|
cmdb_view.CalcSizes(s, cmdb_size, cmdb_addr);
|
||||||
|
@ -1,35 +1,183 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "common/io_file.h"
|
||||||
|
#include "core/devtools/options.h"
|
||||||
|
#include "imgui_internal.h"
|
||||||
#include "reg_view.h"
|
#include "reg_view.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define popen _popen
|
||||||
|
#define pclose _pclose
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace ImGui;
|
using namespace ImGui;
|
||||||
|
|
||||||
|
static std::optional<std::string> exec_cli(const char* cli) {
|
||||||
|
std::array<char, 64> buffer{};
|
||||||
|
std::string output;
|
||||||
|
const auto f = popen(cli, "r");
|
||||||
|
if (!f) {
|
||||||
|
pclose(f);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
while (fgets(buffer.data(), buffer.size(), f)) {
|
||||||
|
output += buffer.data();
|
||||||
|
}
|
||||||
|
pclose(f);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Core::Devtools::Widget {
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
void RegView::ProcessShader(int shader_id) {
|
||||||
|
auto shader = data.stages[shader_id];
|
||||||
|
|
||||||
|
std::string shader_dis;
|
||||||
|
|
||||||
|
if (Options.disassembly_cli.empty()) {
|
||||||
|
shader_dis = "No disassembler set";
|
||||||
|
} else {
|
||||||
|
auto bin_path = std::filesystem::temp_directory_path() / "shadps4_tmp_shader.bin";
|
||||||
|
|
||||||
|
constexpr std::string_view src_arg = "{src}";
|
||||||
|
std::string cli = Options.disassembly_cli;
|
||||||
|
const auto pos = cli.find(src_arg);
|
||||||
|
if (pos == std::string::npos) {
|
||||||
|
DebugState.ShowDebugMessage("Disassembler CLI does not contain {src} argument");
|
||||||
|
} else {
|
||||||
|
cli.replace(pos, src_arg.size(), "\"" + bin_path.string() + "\"");
|
||||||
|
Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Write);
|
||||||
|
file.Write(shader.code);
|
||||||
|
file.Close();
|
||||||
|
|
||||||
|
auto result = exec_cli(cli.c_str());
|
||||||
|
shader_dis = result.value_or("Could not disassemble shader");
|
||||||
|
if (shader_dis.empty()) {
|
||||||
|
shader_dis = "Disassembly empty or failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::remove(bin_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryEditor hex_view;
|
||||||
|
hex_view.Open = true;
|
||||||
|
hex_view.ReadOnly = true;
|
||||||
|
hex_view.Cols = 16;
|
||||||
|
hex_view.OptShowAscii = false;
|
||||||
|
|
||||||
|
TextEditor dis_view;
|
||||||
|
dis_view.SetPalette(TextEditor::GetDarkPalette());
|
||||||
|
dis_view.SetReadOnly(true);
|
||||||
|
dis_view.SetText(shader_dis);
|
||||||
|
|
||||||
|
ShaderCache cache{
|
||||||
|
.hex_view = hex_view,
|
||||||
|
.dis_view = dis_view,
|
||||||
|
.user_data = shader.user_data.user_data,
|
||||||
|
};
|
||||||
|
shader_decomp.emplace(shader_id, std::move(cache));
|
||||||
|
}
|
||||||
|
|
||||||
RegView::RegView() {
|
RegView::RegView() {
|
||||||
static int unique_id = 0;
|
static int unique_id = 0;
|
||||||
id = unique_id++;
|
id = unique_id++;
|
||||||
|
|
||||||
|
char name[64];
|
||||||
|
snprintf(name, sizeof(name), "BatchView###reg_dump_%d", id);
|
||||||
|
Begin(name);
|
||||||
|
SetWindowPos({400.0f, 200.0f});
|
||||||
|
|
||||||
|
char dock_name[64];
|
||||||
|
snprintf(dock_name, sizeof(dock_name), "BatchView###reg_dump_%d/dock_space", id);
|
||||||
|
auto root_dock_id = ImHashStr(dock_name);
|
||||||
|
DockSpace(root_dock_id, {}, ImGuiDockNodeFlags_AutoHideTabBar);
|
||||||
|
|
||||||
|
End();
|
||||||
|
|
||||||
|
ImGuiID up1, down1;
|
||||||
|
|
||||||
|
auto center = DockBuilderAddNode(root_dock_id);
|
||||||
|
DockBuilderSplitNode(center, ImGuiDir_Up, 0.2f, &up1, &down1);
|
||||||
|
|
||||||
|
snprintf(name, sizeof(name), "User data###reg_dump_%d/user_data", id);
|
||||||
|
DockBuilderDockWindow(name, up1);
|
||||||
|
|
||||||
|
snprintf(name, sizeof(name), "Disassembly###reg_dump_%d/disassembly", id);
|
||||||
|
DockBuilderDockWindow(name, down1);
|
||||||
|
|
||||||
|
DockBuilderFinish(root_dock_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegView::SetData(DebugStateType::RegDump data) {
|
||||||
|
this->data = std::move(data);
|
||||||
|
// clear cache
|
||||||
|
selected_shader = -1;
|
||||||
|
shader_decomp.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegView::Draw() {
|
void RegView::Draw() {
|
||||||
char name[32];
|
|
||||||
snprintf(name, sizeof(name), "Reg view###reg_dump_%d", id);
|
char name[64];
|
||||||
if (Begin(name, &open, ImGuiWindowFlags_NoSavedSettings)) {
|
snprintf(name, sizeof(name), "BatchView###reg_dump_%d", id);
|
||||||
if (BeginTable("Enable shaders", 2)) {
|
if (Begin(name, &open, ImGuiWindowFlags_MenuBar)) {
|
||||||
for (int i = 0; i < DebugStateType::RegDump::MaxShaderStages; i++) {
|
const char* names[] = {"vs", "ps", "gs", "es", "hs", "ls"};
|
||||||
TableNextRow();
|
|
||||||
TableSetColumnIndex(0);
|
if (BeginMenuBar()) {
|
||||||
const char* names[] = {"vs", "ps", "gs", "es", "hs", "ls"};
|
if (BeginMenu("Stage")) {
|
||||||
Text("%s", names[i]);
|
for (int i = 0; i < DebugStateType::RegDump::MaxShaderStages; i++) {
|
||||||
TableSetColumnIndex(1);
|
if (data.regs.stage_enable.IsStageEnabled(i)) {
|
||||||
Text("%X", data.regs.stage_enable.IsStageEnabled(i));
|
bool selected = selected_shader == i;
|
||||||
TableSetColumnIndex(0);
|
if (Selectable(names[i], &selected)) {
|
||||||
|
selected_shader = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndMenu();
|
||||||
}
|
}
|
||||||
EndTable();
|
if (BeginMenu("Windows")) {
|
||||||
|
Checkbox("User data", &show_user_data);
|
||||||
|
Checkbox("Disassembly", &show_disassembly);
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
EndMenuBar();
|
||||||
}
|
}
|
||||||
|
if (selected_shader == -1) {
|
||||||
|
Text("Select a stage");
|
||||||
|
End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char dock_name[64];
|
||||||
|
snprintf(dock_name, sizeof(dock_name), "BatchView###reg_dump_%d/dock_space", id);
|
||||||
|
auto root_dock_id = ImHashStr(dock_name);
|
||||||
|
DockSpace(root_dock_id, {}, ImGuiDockNodeFlags_AutoHideTabBar);
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
|
||||||
|
auto shader_cache = shader_decomp.find(selected_shader);
|
||||||
|
if (shader_cache == shader_decomp.end()) {
|
||||||
|
ProcessShader(selected_shader);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto& shader = shader_cache->second;
|
||||||
|
|
||||||
|
snprintf(name, sizeof(name), "User data###reg_dump_%d/user_data", id);
|
||||||
|
if (Begin(name, &show_user_data)) {
|
||||||
|
shader.hex_view.DrawContents(shader.user_data.data(), shader.user_data.size());
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
|
||||||
|
snprintf(name, sizeof(name), "Disassembly###reg_dump_%d/disassembly", id);
|
||||||
|
if (Begin(name, &show_disassembly)) {
|
||||||
|
shader.dis_view.Render("Disassembly", GetContentRegionAvail());
|
||||||
}
|
}
|
||||||
End();
|
End();
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,36 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "core/debug_state.h"
|
#include "core/debug_state.h"
|
||||||
|
#include "imgui_memory_editor.h"
|
||||||
|
#include "text_editor.h"
|
||||||
|
|
||||||
namespace Core::Devtools::Widget {
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
struct ShaderCache {
|
||||||
|
MemoryEditor hex_view;
|
||||||
|
TextEditor dis_view;
|
||||||
|
Vulkan::Liverpool::UserData user_data;
|
||||||
|
};
|
||||||
|
|
||||||
class RegView {
|
class RegView {
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
|
DebugStateType::RegDump data;
|
||||||
|
|
||||||
|
std::unordered_map<int, ShaderCache> shader_decomp;
|
||||||
|
int selected_shader{-1};
|
||||||
|
bool show_user_data{true};
|
||||||
|
bool show_disassembly{true};
|
||||||
|
|
||||||
|
void ProcessShader(int shader_id);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool open = false;
|
bool open = false;
|
||||||
|
|
||||||
DebugStateType::RegDump data;
|
|
||||||
|
|
||||||
RegView();
|
RegView();
|
||||||
|
|
||||||
|
void SetData(DebugStateType::RegDump data);
|
||||||
|
|
||||||
void Draw();
|
void Draw();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
2334
src/core/devtools/widget/text_editor.cpp
Normal file
2334
src/core/devtools/widget/text_editor.cpp
Normal file
File diff suppressed because it is too large
Load Diff
408
src/core/devtools/widget/text_editor.h
Normal file
408
src/core/devtools/widget/text_editor.h
Normal file
@ -0,0 +1,408 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright (c) 2017 BalazsJako
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
// source: https://github.com/BalazsJako/ImGuiColorTextEdit
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <regex>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "imgui.h"
|
||||||
|
|
||||||
|
namespace Core::Devtools::Widget {
|
||||||
|
|
||||||
|
class TextEditor {
|
||||||
|
public:
|
||||||
|
enum class PaletteIndex {
|
||||||
|
Default,
|
||||||
|
Keyword,
|
||||||
|
Number,
|
||||||
|
String,
|
||||||
|
CharLiteral,
|
||||||
|
Punctuation,
|
||||||
|
Preprocessor,
|
||||||
|
Identifier,
|
||||||
|
KnownIdentifier,
|
||||||
|
PreprocIdentifier,
|
||||||
|
Comment,
|
||||||
|
MultiLineComment,
|
||||||
|
Background,
|
||||||
|
Cursor,
|
||||||
|
Selection,
|
||||||
|
ErrorMarker,
|
||||||
|
Breakpoint,
|
||||||
|
LineNumber,
|
||||||
|
CurrentLineFill,
|
||||||
|
CurrentLineFillInactive,
|
||||||
|
CurrentLineEdge,
|
||||||
|
Max
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class SelectionMode { Normal, Word, Line };
|
||||||
|
|
||||||
|
struct Breakpoint {
|
||||||
|
int mLine;
|
||||||
|
bool mEnabled;
|
||||||
|
std::string mCondition;
|
||||||
|
|
||||||
|
Breakpoint() : mLine(-1), mEnabled(false) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Represents a character coordinate from the user's point of view,
|
||||||
|
// i. e. consider an uniform grid (assuming fixed-width font) on the
|
||||||
|
// screen as it is rendered, and each cell has its own coordinate, starting from 0.
|
||||||
|
// Tabs are counted as [1..mTabSize] count empty spaces, depending on
|
||||||
|
// how many space is necessary to reach the next tab stop.
|
||||||
|
// For example, coordinate (1, 5) represents the character 'B' in a line "\tABC", when mTabSize
|
||||||
|
// = 4, because it is rendered as " ABC" on the screen.
|
||||||
|
struct Coordinates {
|
||||||
|
int mLine, mColumn;
|
||||||
|
Coordinates() : mLine(0), mColumn(0) {}
|
||||||
|
Coordinates(int aLine, int aColumn) : mLine(aLine), mColumn(aColumn) {
|
||||||
|
ASSERT(aLine >= 0);
|
||||||
|
ASSERT(aColumn >= 0);
|
||||||
|
}
|
||||||
|
static Coordinates Invalid() {
|
||||||
|
static Coordinates invalid(-1, -1);
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Coordinates& o) const {
|
||||||
|
return mLine == o.mLine && mColumn == o.mColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const Coordinates& o) const {
|
||||||
|
return mLine != o.mLine || mColumn != o.mColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const Coordinates& o) const {
|
||||||
|
if (mLine != o.mLine)
|
||||||
|
return mLine < o.mLine;
|
||||||
|
return mColumn < o.mColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>(const Coordinates& o) const {
|
||||||
|
if (mLine != o.mLine)
|
||||||
|
return mLine > o.mLine;
|
||||||
|
return mColumn > o.mColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<=(const Coordinates& o) const {
|
||||||
|
if (mLine != o.mLine)
|
||||||
|
return mLine < o.mLine;
|
||||||
|
return mColumn <= o.mColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>=(const Coordinates& o) const {
|
||||||
|
if (mLine != o.mLine)
|
||||||
|
return mLine > o.mLine;
|
||||||
|
return mColumn >= o.mColumn;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Identifier {
|
||||||
|
Coordinates mLocation;
|
||||||
|
std::string mDeclaration;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::string String;
|
||||||
|
typedef std::unordered_map<std::string, Identifier> Identifiers;
|
||||||
|
typedef std::unordered_set<std::string> Keywords;
|
||||||
|
typedef std::map<int, std::string> ErrorMarkers;
|
||||||
|
typedef std::unordered_set<int> Breakpoints;
|
||||||
|
typedef std::array<ImU32, (unsigned)PaletteIndex::Max> Palette;
|
||||||
|
typedef uint8_t Char;
|
||||||
|
|
||||||
|
struct Glyph {
|
||||||
|
Char mChar;
|
||||||
|
PaletteIndex mColorIndex = PaletteIndex::Default;
|
||||||
|
bool mComment : 1;
|
||||||
|
bool mMultiLineComment : 1;
|
||||||
|
bool mPreprocessor : 1;
|
||||||
|
|
||||||
|
Glyph(Char aChar, PaletteIndex aColorIndex)
|
||||||
|
: mChar(aChar), mColorIndex(aColorIndex), mComment(false), mMultiLineComment(false),
|
||||||
|
mPreprocessor(false) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<Glyph> Line;
|
||||||
|
typedef std::vector<Line> Lines;
|
||||||
|
|
||||||
|
struct LanguageDefinition {
|
||||||
|
typedef std::pair<std::string, PaletteIndex> TokenRegexString;
|
||||||
|
typedef std::vector<TokenRegexString> TokenRegexStrings;
|
||||||
|
typedef bool (*TokenizeCallback)(const char* in_begin, const char* in_end,
|
||||||
|
const char*& out_begin, const char*& out_end,
|
||||||
|
PaletteIndex& paletteIndex);
|
||||||
|
|
||||||
|
std::string mName;
|
||||||
|
Keywords mKeywords;
|
||||||
|
Identifiers mIdentifiers;
|
||||||
|
Identifiers mPreprocIdentifiers;
|
||||||
|
std::string mCommentStart, mCommentEnd, mSingleLineComment;
|
||||||
|
char mPreprocChar;
|
||||||
|
bool mAutoIndentation;
|
||||||
|
|
||||||
|
TokenizeCallback mTokenize;
|
||||||
|
|
||||||
|
TokenRegexStrings mTokenRegexStrings;
|
||||||
|
|
||||||
|
bool mCaseSensitive;
|
||||||
|
|
||||||
|
LanguageDefinition()
|
||||||
|
: mPreprocChar('#'), mAutoIndentation(true), mTokenize(nullptr), mCaseSensitive(true) {}
|
||||||
|
|
||||||
|
static const LanguageDefinition& GLSL();
|
||||||
|
};
|
||||||
|
|
||||||
|
TextEditor();
|
||||||
|
~TextEditor();
|
||||||
|
|
||||||
|
void SetLanguageDefinition(const LanguageDefinition& aLanguageDef);
|
||||||
|
const LanguageDefinition& GetLanguageDefinition() const {
|
||||||
|
return mLanguageDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Palette& GetPalette() const {
|
||||||
|
return mPaletteBase;
|
||||||
|
}
|
||||||
|
void SetPalette(const Palette& aValue);
|
||||||
|
|
||||||
|
void SetErrorMarkers(const ErrorMarkers& aMarkers) {
|
||||||
|
mErrorMarkers = aMarkers;
|
||||||
|
}
|
||||||
|
void SetBreakpoints(const Breakpoints& aMarkers) {
|
||||||
|
mBreakpoints = aMarkers;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Render(const char* aTitle, const ImVec2& aSize = ImVec2(), bool aBorder = false);
|
||||||
|
void SetText(const std::string& aText);
|
||||||
|
std::string GetText() const;
|
||||||
|
|
||||||
|
void SetTextLines(const std::vector<std::string>& aLines);
|
||||||
|
std::vector<std::string> GetTextLines() const;
|
||||||
|
|
||||||
|
std::string GetSelectedText() const;
|
||||||
|
std::string GetCurrentLineText() const;
|
||||||
|
|
||||||
|
int GetTotalLines() const {
|
||||||
|
return (int)mLines.size();
|
||||||
|
}
|
||||||
|
bool IsOverwrite() const {
|
||||||
|
return mOverwrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetReadOnly(bool aValue);
|
||||||
|
bool IsReadOnly() const {
|
||||||
|
return mReadOnly;
|
||||||
|
}
|
||||||
|
bool IsTextChanged() const {
|
||||||
|
return mTextChanged;
|
||||||
|
}
|
||||||
|
bool IsCursorPositionChanged() const {
|
||||||
|
return mCursorPositionChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsColorizerEnabled() const {
|
||||||
|
return mColorizerEnabled;
|
||||||
|
}
|
||||||
|
void SetColorizerEnable(bool aValue);
|
||||||
|
|
||||||
|
Coordinates GetCursorPosition() const {
|
||||||
|
return GetActualCursorCoordinates();
|
||||||
|
}
|
||||||
|
void SetCursorPosition(const Coordinates& aPosition);
|
||||||
|
|
||||||
|
inline void SetHandleMouseInputs(bool aValue) {
|
||||||
|
mHandleMouseInputs = aValue;
|
||||||
|
}
|
||||||
|
inline bool IsHandleMouseInputsEnabled() const {
|
||||||
|
return mHandleKeyboardInputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetHandleKeyboardInputs(bool aValue) {
|
||||||
|
mHandleKeyboardInputs = aValue;
|
||||||
|
}
|
||||||
|
inline bool IsHandleKeyboardInputsEnabled() const {
|
||||||
|
return mHandleKeyboardInputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetImGuiChildIgnored(bool aValue) {
|
||||||
|
mIgnoreImGuiChild = aValue;
|
||||||
|
}
|
||||||
|
inline bool IsImGuiChildIgnored() const {
|
||||||
|
return mIgnoreImGuiChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetShowWhitespaces(bool aValue) {
|
||||||
|
mShowWhitespaces = aValue;
|
||||||
|
}
|
||||||
|
inline bool IsShowingWhitespaces() const {
|
||||||
|
return mShowWhitespaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTabSize(int aValue);
|
||||||
|
inline int GetTabSize() const {
|
||||||
|
return mTabSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InsertText(const std::string& aValue);
|
||||||
|
void InsertText(const char* aValue);
|
||||||
|
|
||||||
|
void MoveUp(int aAmount = 1, bool aSelect = false);
|
||||||
|
void MoveDown(int aAmount = 1, bool aSelect = false);
|
||||||
|
void MoveLeft(int aAmount = 1, bool aSelect = false, bool aWordMode = false);
|
||||||
|
void MoveRight(int aAmount = 1, bool aSelect = false, bool aWordMode = false);
|
||||||
|
void MoveTop(bool aSelect = false);
|
||||||
|
void MoveBottom(bool aSelect = false);
|
||||||
|
void MoveHome(bool aSelect = false);
|
||||||
|
void MoveEnd(bool aSelect = false);
|
||||||
|
|
||||||
|
void SetSelectionStart(const Coordinates& aPosition);
|
||||||
|
void SetSelectionEnd(const Coordinates& aPosition);
|
||||||
|
void SetSelection(const Coordinates& aStart, const Coordinates& aEnd,
|
||||||
|
SelectionMode aMode = SelectionMode::Normal);
|
||||||
|
void SelectWordUnderCursor();
|
||||||
|
void SelectAll();
|
||||||
|
bool HasSelection() const;
|
||||||
|
|
||||||
|
void Copy();
|
||||||
|
void Cut();
|
||||||
|
void Paste();
|
||||||
|
void Delete();
|
||||||
|
|
||||||
|
bool CanUndo() const;
|
||||||
|
bool CanRedo() const;
|
||||||
|
void Undo(int aSteps = 1);
|
||||||
|
void Redo(int aSteps = 1);
|
||||||
|
|
||||||
|
static const Palette& GetDarkPalette();
|
||||||
|
static const Palette& GetLightPalette();
|
||||||
|
static const Palette& GetRetroBluePalette();
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::vector<std::pair<std::regex, PaletteIndex>> RegexList;
|
||||||
|
|
||||||
|
struct EditorState {
|
||||||
|
Coordinates mSelectionStart;
|
||||||
|
Coordinates mSelectionEnd;
|
||||||
|
Coordinates mCursorPosition;
|
||||||
|
};
|
||||||
|
|
||||||
|
class UndoRecord {
|
||||||
|
public:
|
||||||
|
UndoRecord() {}
|
||||||
|
~UndoRecord() {}
|
||||||
|
|
||||||
|
UndoRecord(const std::string& aAdded, const TextEditor::Coordinates aAddedStart,
|
||||||
|
const TextEditor::Coordinates aAddedEnd,
|
||||||
|
|
||||||
|
const std::string& aRemoved, const TextEditor::Coordinates aRemovedStart,
|
||||||
|
const TextEditor::Coordinates aRemovedEnd,
|
||||||
|
|
||||||
|
TextEditor::EditorState& aBefore, TextEditor::EditorState& aAfter);
|
||||||
|
|
||||||
|
void Undo(TextEditor* aEditor);
|
||||||
|
void Redo(TextEditor* aEditor);
|
||||||
|
|
||||||
|
std::string mAdded;
|
||||||
|
Coordinates mAddedStart;
|
||||||
|
Coordinates mAddedEnd;
|
||||||
|
|
||||||
|
std::string mRemoved;
|
||||||
|
Coordinates mRemovedStart;
|
||||||
|
Coordinates mRemovedEnd;
|
||||||
|
|
||||||
|
EditorState mBefore;
|
||||||
|
EditorState mAfter;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<UndoRecord> UndoBuffer;
|
||||||
|
|
||||||
|
void ProcessInputs();
|
||||||
|
void Colorize(int aFromLine = 0, int aCount = -1);
|
||||||
|
void ColorizeRange(int aFromLine = 0, int aToLine = 0);
|
||||||
|
void ColorizeInternal();
|
||||||
|
float TextDistanceToLineStart(const Coordinates& aFrom) const;
|
||||||
|
void EnsureCursorVisible();
|
||||||
|
int GetPageSize() const;
|
||||||
|
std::string GetText(const Coordinates& aStart, const Coordinates& aEnd) const;
|
||||||
|
Coordinates GetActualCursorCoordinates() const;
|
||||||
|
Coordinates SanitizeCoordinates(const Coordinates& aValue) const;
|
||||||
|
void Advance(Coordinates& aCoordinates) const;
|
||||||
|
void DeleteRange(const Coordinates& aStart, const Coordinates& aEnd);
|
||||||
|
int InsertTextAt(Coordinates& aWhere, const char* aValue);
|
||||||
|
void AddUndo(UndoRecord& aValue);
|
||||||
|
Coordinates ScreenPosToCoordinates(const ImVec2& aPosition) const;
|
||||||
|
Coordinates FindWordStart(const Coordinates& aFrom) const;
|
||||||
|
Coordinates FindWordEnd(const Coordinates& aFrom) const;
|
||||||
|
Coordinates FindNextWord(const Coordinates& aFrom) const;
|
||||||
|
int GetCharacterIndex(const Coordinates& aCoordinates) const;
|
||||||
|
int GetCharacterColumn(int aLine, int aIndex) const;
|
||||||
|
int GetLineCharacterCount(int aLine) const;
|
||||||
|
int GetLineMaxColumn(int aLine) const;
|
||||||
|
bool IsOnWordBoundary(const Coordinates& aAt) const;
|
||||||
|
void RemoveLine(int aStart, int aEnd);
|
||||||
|
void RemoveLine(int aIndex);
|
||||||
|
Line& InsertLine(int aIndex);
|
||||||
|
void EnterCharacter(ImWchar aChar, bool aShift);
|
||||||
|
void Backspace();
|
||||||
|
void DeleteSelection();
|
||||||
|
std::string GetWordUnderCursor() const;
|
||||||
|
std::string GetWordAt(const Coordinates& aCoords) const;
|
||||||
|
ImU32 GetGlyphColor(const Glyph& aGlyph) const;
|
||||||
|
|
||||||
|
void HandleKeyboardInputs();
|
||||||
|
void HandleMouseInputs();
|
||||||
|
void Render();
|
||||||
|
|
||||||
|
float mLineSpacing;
|
||||||
|
Lines mLines;
|
||||||
|
EditorState mState;
|
||||||
|
UndoBuffer mUndoBuffer;
|
||||||
|
int mUndoIndex;
|
||||||
|
|
||||||
|
int mTabSize;
|
||||||
|
bool mOverwrite;
|
||||||
|
bool mReadOnly;
|
||||||
|
bool mWithinRender;
|
||||||
|
bool mScrollToCursor;
|
||||||
|
bool mScrollToTop;
|
||||||
|
bool mTextChanged;
|
||||||
|
bool mColorizerEnabled;
|
||||||
|
float mTextStart; // position (in pixels) where a code line starts relative to the left of the
|
||||||
|
// TextEditor.
|
||||||
|
int mLeftMargin;
|
||||||
|
bool mCursorPositionChanged;
|
||||||
|
int mColorRangeMin, mColorRangeMax;
|
||||||
|
SelectionMode mSelectionMode;
|
||||||
|
bool mHandleKeyboardInputs;
|
||||||
|
bool mHandleMouseInputs;
|
||||||
|
bool mIgnoreImGuiChild;
|
||||||
|
bool mShowWhitespaces;
|
||||||
|
|
||||||
|
Palette mPaletteBase;
|
||||||
|
Palette mPalette;
|
||||||
|
LanguageDefinition mLanguageDefinition;
|
||||||
|
RegexList mRegexList;
|
||||||
|
|
||||||
|
bool mCheckComments;
|
||||||
|
Breakpoints mBreakpoints;
|
||||||
|
ErrorMarkers mErrorMarkers;
|
||||||
|
ImVec2 mCharAdvance;
|
||||||
|
Coordinates mInteractiveStart, mInteractiveEnd;
|
||||||
|
std::string mLineBuffer;
|
||||||
|
uint64_t mStartTime;
|
||||||
|
|
||||||
|
float mLastClick;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Core::Devtools::Widget
|
@ -75,7 +75,7 @@ public:
|
|||||||
std::min(io.DisplaySize.y, 300.0f),
|
std::min(io.DisplaySize.y, 300.0f),
|
||||||
};
|
};
|
||||||
|
|
||||||
CentralizeWindow();
|
CentralizeNextWindow();
|
||||||
SetNextWindowSize(window_size);
|
SetNextWindowSize(window_size);
|
||||||
SetNextWindowCollapsed(false);
|
SetNextWindowCollapsed(false);
|
||||||
if (first_render || !io.NavActive) {
|
if (first_render || !io.NavActive) {
|
||||||
|
@ -505,11 +505,6 @@ void PS4_SYSV_ABI sceGnmDingDong(u32 gnm_vqid, u32 next_offs_dw) {
|
|||||||
: (asc_queue.ring_size_dw << 2u) - *asc_queue.read_addr;
|
: (asc_queue.ring_size_dw << 2u) - *asc_queue.read_addr;
|
||||||
const std::span acb_span{acb_ptr, acb_size >> 2u};
|
const std::span acb_span{acb_ptr, acb_size >> 2u};
|
||||||
|
|
||||||
liverpool->SubmitAsc(vqid, acb_span);
|
|
||||||
|
|
||||||
*asc_queue.read_addr += acb_size;
|
|
||||||
*asc_queue.read_addr %= asc_queue.ring_size_dw * 4;
|
|
||||||
|
|
||||||
if (DebugState.DumpingCurrentFrame()) {
|
if (DebugState.DumpingCurrentFrame()) {
|
||||||
static auto last_frame_num = -1LL;
|
static auto last_frame_num = -1LL;
|
||||||
static u32 seq_num{};
|
static u32 seq_num{};
|
||||||
@ -542,6 +537,10 @@ void PS4_SYSV_ABI sceGnmDingDong(u32 gnm_vqid, u32 next_offs_dw) {
|
|||||||
.base_addr = base_addr,
|
.base_addr = base_addr,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
liverpool->SubmitAsc(vqid, acb_span);
|
||||||
|
|
||||||
|
*asc_queue.read_addr += acb_size;
|
||||||
|
*asc_queue.read_addr %= asc_queue.ring_size_dw * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceGnmDingDongForWorkload() {
|
int PS4_SYSV_ABI sceGnmDingDongForWorkload() {
|
||||||
@ -2165,7 +2164,6 @@ s32 PS4_SYSV_ABI sceGnmSubmitCommandBuffers(u32 count, const u32* dcb_gpu_addrs[
|
|||||||
const auto& dcb_span = std::span{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{ccb, ccb_size_dw};
|
const auto& ccb_span = std::span{ccb, ccb_size_dw};
|
||||||
|
|
||||||
liverpool->SubmitGfx(dcb_span, ccb_span);
|
|
||||||
if (DebugState.DumpingCurrentFrame()) {
|
if (DebugState.DumpingCurrentFrame()) {
|
||||||
static auto last_frame_num = -1LL;
|
static auto last_frame_num = -1LL;
|
||||||
static u32 seq_num{};
|
static u32 seq_num{};
|
||||||
@ -2193,6 +2191,7 @@ s32 PS4_SYSV_ABI sceGnmSubmitCommandBuffers(u32 count, const u32* dcb_gpu_addrs[
|
|||||||
.base_addr = reinterpret_cast<uintptr_t>(ccb),
|
.base_addr = reinterpret_cast<uintptr_t>(ccb),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
liverpool->SubmitGfx(dcb_span, ccb_span);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
|
@ -402,7 +402,7 @@ void SaveDialogUi::Draw() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
CentralizeWindow();
|
CentralizeNextWindow();
|
||||||
SetNextWindowSize(window_size);
|
SetNextWindowSize(window_size);
|
||||||
SetNextWindowCollapsed(false);
|
SetNextWindowCollapsed(false);
|
||||||
if (first_render || !io.NavActive) {
|
if (first_render || !io.NavActive) {
|
||||||
|
@ -256,7 +256,7 @@ void MsgDialogUi::Draw() {
|
|||||||
std::min(io.DisplaySize.y, 300.0f),
|
std::min(io.DisplaySize.y, 300.0f),
|
||||||
};
|
};
|
||||||
|
|
||||||
CentralizeWindow();
|
CentralizeNextWindow();
|
||||||
SetNextWindowSize(window_size);
|
SetNextWindowSize(window_size);
|
||||||
SetNextWindowCollapsed(false);
|
SetNextWindowCollapsed(false);
|
||||||
if (first_render || !io.NavActive) {
|
if (first_render || !io.NavActive) {
|
||||||
|
@ -25,11 +25,16 @@ inline float FastInFastOutCubic(float x) {
|
|||||||
|
|
||||||
} // namespace Easing
|
} // namespace Easing
|
||||||
|
|
||||||
inline void CentralizeWindow() {
|
inline void CentralizeNextWindow() {
|
||||||
const auto display_size = GetIO().DisplaySize;
|
const auto display_size = GetIO().DisplaySize;
|
||||||
SetNextWindowPos(display_size / 2.0f, ImGuiCond_Always, {0.5f});
|
SetNextWindowPos(display_size / 2.0f, ImGuiCond_Always, {0.5f});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void CentralizeWindow() {
|
||||||
|
const auto display_size = GetIO().DisplaySize;
|
||||||
|
SetWindowPos(display_size / 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
inline void KeepWindowInside(ImVec2 display_size = GetIO().DisplaySize) {
|
inline void KeepWindowInside(ImVec2 display_size = GetIO().DisplaySize) {
|
||||||
const auto cur_pos = GetWindowPos();
|
const auto cur_pos = GetWindowPos();
|
||||||
if (cur_pos.x < 0.0f || cur_pos.y < 0.0f) {
|
if (cur_pos.x < 0.0f || cur_pos.y < 0.0f) {
|
||||||
|
@ -188,6 +188,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||||||
TracyFiberEnter(dcb_task_name);
|
TracyFiberEnter(dcb_task_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto base_addr = reinterpret_cast<uintptr_t>(dcb.data());
|
||||||
while (!dcb.empty()) {
|
while (!dcb.empty()) {
|
||||||
const auto* header = reinterpret_cast<const PM4Header*>(dcb.data());
|
const auto* header = reinterpret_cast<const PM4Header*>(dcb.data());
|
||||||
const u32 type = header->type;
|
const u32 type = header->type;
|
||||||
@ -361,7 +362,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||||||
regs.num_indices = draw_index->index_count;
|
regs.num_indices = draw_index->index_count;
|
||||||
regs.draw_initiator = draw_index->draw_initiator;
|
regs.draw_initiator = draw_index->draw_initiator;
|
||||||
if (DebugState.DumpingCurrentReg()) {
|
if (DebugState.DumpingCurrentReg()) {
|
||||||
DebugState.PushRegsDump(reinterpret_cast<uintptr_t>(header), regs);
|
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs);
|
||||||
}
|
}
|
||||||
if (rasterizer) {
|
if (rasterizer) {
|
||||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||||
@ -378,7 +379,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||||||
regs.num_indices = draw_index_off->index_count;
|
regs.num_indices = draw_index_off->index_count;
|
||||||
regs.draw_initiator = draw_index_off->draw_initiator;
|
regs.draw_initiator = draw_index_off->draw_initiator;
|
||||||
if (DebugState.DumpingCurrentReg()) {
|
if (DebugState.DumpingCurrentReg()) {
|
||||||
DebugState.PushRegsDump(reinterpret_cast<uintptr_t>(header), regs);
|
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs);
|
||||||
}
|
}
|
||||||
if (rasterizer) {
|
if (rasterizer) {
|
||||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||||
@ -394,7 +395,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||||||
regs.num_indices = draw_index->index_count;
|
regs.num_indices = draw_index->index_count;
|
||||||
regs.draw_initiator = draw_index->draw_initiator;
|
regs.draw_initiator = draw_index->draw_initiator;
|
||||||
if (DebugState.DumpingCurrentReg()) {
|
if (DebugState.DumpingCurrentReg()) {
|
||||||
DebugState.PushRegsDump(reinterpret_cast<uintptr_t>(header), regs);
|
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs);
|
||||||
}
|
}
|
||||||
if (rasterizer) {
|
if (rasterizer) {
|
||||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||||
@ -410,7 +411,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||||||
const auto ib_address = mapped_queues[GfxQueueId].indirect_args_addr;
|
const auto ib_address = mapped_queues[GfxQueueId].indirect_args_addr;
|
||||||
const auto size = sizeof(PM4CmdDrawIndirect::DrawInstancedArgs);
|
const auto size = sizeof(PM4CmdDrawIndirect::DrawInstancedArgs);
|
||||||
if (DebugState.DumpingCurrentReg()) {
|
if (DebugState.DumpingCurrentReg()) {
|
||||||
DebugState.PushRegsDump(reinterpret_cast<uintptr_t>(header), regs);
|
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs);
|
||||||
}
|
}
|
||||||
if (rasterizer) {
|
if (rasterizer) {
|
||||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||||
@ -427,7 +428,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||||||
const auto ib_address = mapped_queues[GfxQueueId].indirect_args_addr;
|
const auto ib_address = mapped_queues[GfxQueueId].indirect_args_addr;
|
||||||
const auto size = sizeof(PM4CmdDrawIndexIndirect::DrawIndexInstancedArgs);
|
const auto size = sizeof(PM4CmdDrawIndexIndirect::DrawIndexInstancedArgs);
|
||||||
if (DebugState.DumpingCurrentReg()) {
|
if (DebugState.DumpingCurrentReg()) {
|
||||||
DebugState.PushRegsDump(reinterpret_cast<uintptr_t>(header), regs);
|
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs);
|
||||||
}
|
}
|
||||||
if (rasterizer) {
|
if (rasterizer) {
|
||||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||||
@ -445,7 +446,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||||||
regs.cs_program.dim_z = dispatch_direct->dim_z;
|
regs.cs_program.dim_z = dispatch_direct->dim_z;
|
||||||
regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator;
|
regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator;
|
||||||
if (DebugState.DumpingCurrentReg()) {
|
if (DebugState.DumpingCurrentReg()) {
|
||||||
DebugState.PushRegsDump(reinterpret_cast<uintptr_t>(header), regs);
|
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs);
|
||||||
}
|
}
|
||||||
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
||||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||||
@ -462,7 +463,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||||||
const auto ib_address = mapped_queues[GfxQueueId].indirect_args_addr;
|
const auto ib_address = mapped_queues[GfxQueueId].indirect_args_addr;
|
||||||
const auto size = sizeof(PM4CmdDispatchIndirect::GroupDimensions);
|
const auto size = sizeof(PM4CmdDispatchIndirect::GroupDimensions);
|
||||||
if (DebugState.DumpingCurrentReg()) {
|
if (DebugState.DumpingCurrentReg()) {
|
||||||
DebugState.PushRegsDump(reinterpret_cast<uintptr_t>(header), regs);
|
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs);
|
||||||
}
|
}
|
||||||
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
||||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||||
@ -598,6 +599,7 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||||||
Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb, int vqid) {
|
Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb, int vqid) {
|
||||||
TracyFiberEnter(acb_task_name);
|
TracyFiberEnter(acb_task_name);
|
||||||
|
|
||||||
|
auto base_addr = reinterpret_cast<uintptr_t>(acb.data());
|
||||||
while (!acb.empty()) {
|
while (!acb.empty()) {
|
||||||
const auto* header = reinterpret_cast<const PM4Header*>(acb.data());
|
const auto* header = reinterpret_cast<const PM4Header*>(acb.data());
|
||||||
const u32 type = header->type;
|
const u32 type = header->type;
|
||||||
@ -643,7 +645,7 @@ Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb, int vqid) {
|
|||||||
regs.cs_program.dim_z = dispatch_direct->dim_z;
|
regs.cs_program.dim_z = dispatch_direct->dim_z;
|
||||||
regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator;
|
regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator;
|
||||||
if (DebugState.DumpingCurrentReg()) {
|
if (DebugState.DumpingCurrentReg()) {
|
||||||
DebugState.PushRegsDump(reinterpret_cast<uintptr_t>(header), regs);
|
DebugState.PushRegsDump(base_addr, reinterpret_cast<uintptr_t>(header), regs);
|
||||||
}
|
}
|
||||||
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
||||||
const auto cmd_address = reinterpret_cast<const void*>(header);
|
const auto cmd_address = reinterpret_cast<const void*>(header);
|
||||||
|
Loading…
Reference in New Issue
Block a user