diff --git a/CMakeLists.txt b/CMakeLists.txt index 55f1172f2..b62806624 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -412,6 +412,8 @@ set(DEV_TOOLS src/core/devtools/layer.cpp src/core/devtools/widget/frame_graph.cpp src/core/devtools/widget/frame_graph.h src/core/devtools/widget/imgui_memory_editor.h + src/core/devtools/widget/memory_map.cpp + src/core/devtools/widget/memory_map.h src/core/devtools/widget/reg_popup.cpp src/core/devtools/widget/reg_popup.h src/core/devtools/widget/reg_view.cpp diff --git a/src/core/devtools/layer.cpp b/src/core/devtools/layer.cpp index 2c4ce20b6..ca7343586 100644 --- a/src/core/devtools/layer.cpp +++ b/src/core/devtools/layer.cpp @@ -14,6 +14,7 @@ #include "video_core/renderer_vulkan/vk_presenter.h" #include "widget/frame_dump.h" #include "widget/frame_graph.h" +#include "widget/memory_map.h" extern std::unique_ptr presenter; @@ -35,6 +36,8 @@ static float debug_popup_timing = 3.0f; static bool just_opened_options = false; +static Widget::MemoryMapViewer memory_map; + // clang-format off static std::string help_text = #include "help.txt" @@ -81,6 +84,12 @@ void L::DrawMenuBar() { } ImGui::EndMenu(); } + if (BeginMenu("Debug")) { + if (MenuItem("Memory map")) { + memory_map.open = true; + } + ImGui::EndMenu(); + } EndMainMenuBar(); } @@ -219,6 +228,10 @@ void L::DrawAdvanced() { EndPopup(); } + + if (memory_map.open) { + memory_map.Draw(); + } } void L::DrawSimple() { diff --git a/src/core/devtools/widget/memory_map.cpp b/src/core/devtools/widget/memory_map.cpp new file mode 100644 index 000000000..afafd2853 --- /dev/null +++ b/src/core/devtools/widget/memory_map.cpp @@ -0,0 +1,134 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include + +#include "core/debug_state.h" +#include "core/memory.h" +#include "memory_map.h" + +using namespace ImGui; + +namespace Core::Devtools::Widget { + +bool MemoryMapViewer::Iterator::DrawLine() { + if (is_vma) { + if (vma.it == vma.end) { + return false; + } + auto m = vma.it->second; + if (m.type == VMAType::Free) { + ++vma.it; + return DrawLine(); + } + TableNextColumn(); + Text("%zX", m.base); + TableNextColumn(); + Text("%zX", m.size); + TableNextColumn(); + Text("%s", magic_enum::enum_name(m.type).data()); + TableNextColumn(); + Text("%s", magic_enum::enum_name(m.prot).data()); + TableNextColumn(); + if (m.is_exec) { + Text("X"); + } + TableNextColumn(); + Text("%s", m.name.c_str()); + ++vma.it; + return true; + } + if (dmem.it == dmem.end) { + return false; + } + auto m = dmem.it->second; + if (m.is_free) { + ++dmem.it; + return DrawLine(); + } + TableNextColumn(); + Text("%llX", m.base); + TableNextColumn(); + Text("%llX", m.size); + TableNextColumn(); + auto type = static_cast<::Libraries::Kernel::MemoryTypes>(m.memory_type); + Text("%s", magic_enum::enum_name(type).data()); + TableNextColumn(); + Text("%d", m.is_pooled); + ++dmem.it; + return true; +} + +void MemoryMapViewer::Draw() { + SetNextWindowSize({600.0f, 500.0f}, ImGuiCond_FirstUseEver); + if (!Begin("Memory map", &open)) { + End(); + return; + } + + auto mem = Memory::Instance(); + std::scoped_lock lck{mem->mutex}; + + { + bool next_showing_vma = showing_vma; + if (showing_vma) { + PushStyleColor(ImGuiCol_Button, ImVec4{1.0f, 0.7f, 0.7f, 1.0f}); + } + if (Button("VMem")) { + next_showing_vma = true; + } + if (showing_vma) { + PopStyleColor(); + } + SameLine(); + if (!showing_vma) { + PushStyleColor(ImGuiCol_Button, ImVec4{1.0f, 0.7f, 0.7f, 1.0f}); + } + if (Button("DMem")) { + next_showing_vma = false; + } + if (!showing_vma) { + PopStyleColor(); + } + showing_vma = next_showing_vma; + } + + Iterator it{}; + if (showing_vma) { + it.is_vma = true; + it.vma.it = mem->vma_map.begin(); + it.vma.end = mem->vma_map.end(); + } else { + it.is_vma = false; + it.dmem.it = mem->dmem_map.begin(); + it.dmem.end = mem->dmem_map.end(); + } + + if (BeginTable("memory_view_table", showing_vma ? 6 : 4, + ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg | + ImGuiTableFlags_SizingFixedFit)) { + if (showing_vma) { + TableSetupColumn("Address"); + TableSetupColumn("Size"); + TableSetupColumn("Type"); + TableSetupColumn("Prot"); + TableSetupColumn("Is Exec"); + TableSetupColumn("Name"); + } else { + TableSetupColumn("Address"); + TableSetupColumn("Size"); + TableSetupColumn("Type"); + TableSetupColumn("Pooled"); + } + TableHeadersRow(); + + while (it.DrawLine()) + ; + EndTable(); + } + + End(); +} + +} // namespace Core::Devtools::Widget \ No newline at end of file diff --git a/src/core/devtools/widget/memory_map.h b/src/core/devtools/widget/memory_map.h new file mode 100644 index 000000000..cc7697c8c --- /dev/null +++ b/src/core/devtools/widget/memory_map.h @@ -0,0 +1,33 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/memory.h" + +namespace Core::Devtools::Widget { + +class MemoryMapViewer { + struct Iterator { + bool is_vma; + struct { + MemoryManager::DMemMap::iterator it; + MemoryManager::DMemMap::iterator end; + } dmem; + struct { + MemoryManager::VMAMap::iterator it; + MemoryManager::VMAMap::iterator end; + } vma; + + bool DrawLine(); + }; + + bool showing_vma = true; + +public: + bool open = false; + + void Draw(); +}; + +} // namespace Core::Devtools::Widget diff --git a/src/core/memory.h b/src/core/memory.h index a9a42e1c2..2efa02763 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -20,6 +20,10 @@ namespace Libraries::Kernel { struct OrbisQueryInfo; } +namespace Core::Devtools::Widget { +class MemoryMapViewer; +} + namespace Core { enum class MemoryProt : u32 { @@ -257,6 +261,8 @@ private: size_t total_flexible_size{}; size_t flexible_usage{}; Vulkan::Rasterizer* rasterizer{}; + + friend class ::Core::Devtools::Widget::MemoryMapViewer; }; using Memory = Common::Singleton;