diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj
index 74a866a63..cb0e1ac12 100644
--- a/src/core/core.vcxproj
+++ b/src/core/core.vcxproj
@@ -51,6 +51,7 @@
+
@@ -75,6 +76,7 @@
+
diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters
index 67d1d3705..4ac36b39f 100644
--- a/src/core/core.vcxproj.filters
+++ b/src/core/core.vcxproj.filters
@@ -20,6 +20,7 @@
+
@@ -45,6 +46,7 @@
+
diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp
index 0c3b05c30..87d896d73 100644
--- a/src/core/gpu.cpp
+++ b/src/core/gpu.cpp
@@ -6,10 +6,9 @@
#include "stb_image_write.h"
#include "system.h"
#include "timers.h"
+#include
Log_SetChannel(GPU);
-bool GPU::DUMP_CPU_TO_VRAM_COPIES = false;
-bool GPU::DUMP_VRAM_TO_CPU_COPIES = false;
static u32 s_cpu_to_vram_dump_id = 1;
static u32 s_vram_to_cpu_dump_id = 1;
@@ -129,7 +128,16 @@ bool GPU::DoState(StateWrapper& sw)
return !sw.HasError();
}
-void GPU::RenderUI() {}
+void GPU::RenderStatistics() {}
+
+void GPU::RenderDebugMenu()
+{
+ ImGui::MenuItem("Show VRAM", nullptr, &m_debug_options.show_vram);
+ ImGui::MenuItem("Dump CPU to VRAM Copies", nullptr, &m_debug_options.dump_cpu_to_vram_copies);
+ ImGui::MenuItem("Dump VRAM to CPU Copies", nullptr, &m_debug_options.dump_vram_to_cpu_copies);
+}
+
+void GPU::UpdateSettings() {}
void GPU::UpdateGPUSTAT()
{
@@ -678,7 +686,7 @@ bool GPU::HandleCopyRectangleCPUToVRAMCommand()
return true;
}
- if (DUMP_CPU_TO_VRAM_COPIES)
+ if (m_debug_options.dump_cpu_to_vram_copies)
{
DumpVRAMToFile(SmallString::FromFormat("cpu_to_vram_copy_%u.png", s_cpu_to_vram_dump_id++), copy_width, copy_height,
sizeof(u16) * copy_width, &m_GP0_command[3], true);
@@ -718,7 +726,7 @@ bool GPU::HandleCopyRectangleVRAMToCPUCommand()
for (const u32 bits : temp)
m_GPUREAD_buffer.push_back(bits);
- if (DUMP_VRAM_TO_CPU_COPIES)
+ if (m_debug_options.dump_vram_to_cpu_copies)
{
DumpVRAMToFile(SmallString::FromFormat("vram_to_cpu_copy_%u.png", s_cpu_to_vram_dump_id++), width, height,
sizeof(u16) * width, temp.data(), true);
diff --git a/src/core/gpu.h b/src/core/gpu.h
index 472241c33..67544e8d9 100644
--- a/src/core/gpu.h
+++ b/src/core/gpu.h
@@ -16,13 +16,33 @@ class Timers;
class GPU
{
public:
+ static constexpr float DISPLAY_ASPECT_RATIO = 4.0f / 3.0f;
+ enum : u32
+ {
+ VRAM_WIDTH = 1024,
+ VRAM_HEIGHT = 512,
+ VRAM_SIZE = VRAM_WIDTH * VRAM_HEIGHT * sizeof(u16),
+ TEXTURE_PAGE_WIDTH = 256,
+ TEXTURE_PAGE_HEIGHT = 256,
+ DOT_TIMER_INDEX = 0,
+ HBLANK_TIMER_INDEX = 1
+ };
+
GPU();
virtual ~GPU();
virtual bool Initialize(System* system, DMA* dma, InterruptController* interrupt_controller, Timers* timers);
virtual void Reset();
virtual bool DoState(StateWrapper& sw);
- virtual void RenderUI();
+
+ // Render statistics debug window.
+ virtual void RenderStatistics();
+
+ // Manipulating debug options.
+ virtual void RenderDebugMenu();
+
+ // Called when settings change.
+ virtual void UpdateSettings();
u32 ReadRegister(u32 offset);
void WriteRegister(u32 offset, u32 value);
@@ -37,15 +57,6 @@ public:
void Execute(TickCount ticks);
protected:
- static constexpr float DISPLAY_ASPECT_RATIO = 4.0f / 3.0f;
- static constexpr u32 VRAM_WIDTH = 1024;
- static constexpr u32 VRAM_HEIGHT = 512;
- static constexpr u32 VRAM_SIZE = VRAM_WIDTH * VRAM_HEIGHT * sizeof(u16);
- static constexpr u32 TEXTURE_PAGE_WIDTH = 256;
- static constexpr u32 TEXTURE_PAGE_HEIGHT = 256;
- static constexpr u32 DOT_TIMER_INDEX = 0;
- static constexpr u32 HBLANK_TIMER_INDEX = 1;
-
static constexpr s32 S11ToS32(u32 value)
{
if (value & (UINT16_C(1) << 10))
@@ -156,6 +167,13 @@ protected:
s32 y() const { return S11ToS32(y_s11); }
};
+ struct DebugOptions
+ {
+ bool show_vram;
+ bool dump_cpu_to_vram_copies;
+ bool dump_vram_to_cpu_copies;
+ };
+
void SoftReset();
// Sets dots per scanline
@@ -331,7 +349,5 @@ protected:
std::vector m_GP0_command;
std::deque m_GPUREAD_buffer;
- // debug options
- static bool DUMP_CPU_TO_VRAM_COPIES;
- static bool DUMP_VRAM_TO_CPU_COPIES;
+ DebugOptions m_debug_options = {};
};
diff --git a/src/core/gpu_hw_opengl.cpp b/src/core/gpu_hw_opengl.cpp
index eaab29c70..897e40fb4 100644
--- a/src/core/gpu_hw_opengl.cpp
+++ b/src/core/gpu_hw_opengl.cpp
@@ -35,9 +35,9 @@ void GPU_HW_OpenGL::Reset()
ClearFramebuffer();
}
-void GPU_HW_OpenGL::RenderUI()
+void GPU_HW_OpenGL::RenderStatistics()
{
- GPU_HW::RenderUI();
+ GPU_HW::RenderStatistics();
ImGui::SetNextWindowSize(ImVec2(300.0f, 130.0f), ImGuiCond_Once);
@@ -48,7 +48,7 @@ void GPU_HW_OpenGL::RenderUI()
m_stats = {};
}
- if (ImGui::Begin("GL Render Statistics"))
+ if (ImGui::Begin("GPU Render Statistics"))
{
ImGui::Columns(2);
ImGui::SetColumnWidth(0, 200.0f);
@@ -72,33 +72,27 @@ void GPU_HW_OpenGL::RenderUI()
ImGui::NextColumn();
ImGui::Text("%s", is_null_frame ? "Yes" : "No");
ImGui::NextColumn();
-
- ImGui::Columns(1);
-
- ImGui::Checkbox("Show VRAM##gpu_gl_show_vram", &m_show_vram);
-
- static constexpr std::array internal_resolution_items = {
- {"1x Internal Resolution", "2x Internal Resolution", "3x Internal Resolution", "4x Internal Resolution",
- "5x Internal Resolution", "6x Internal Resolution", "7x Internal Resolution", "8x Internal Resolution",
- "9x Internal Resolution", "10x Internal Resolution", "11x Internal Resolution", "12x Internal Resolution",
- "13x Internal Resolution", "14x Internal Resolution", "15x Internal Resolution", "16x Internal Resolution"}};
-
- int internal_resolution_item =
- std::clamp(static_cast(m_resolution_scale) - 1, 0, static_cast(internal_resolution_items.size()));
- if (ImGui::Combo("##gpu_internal_resolution", &internal_resolution_item, internal_resolution_items.data(),
- static_cast(internal_resolution_items.size())))
- {
- m_resolution_scale = static_cast(internal_resolution_item + 1);
- m_system->GetHostInterface()->AddOSDMessage(
- TinyString::FromFormat("Internal resolution changed to %ux, recompiling programs", m_resolution_scale));
- CreateFramebuffer();
- CompilePrograms();
- }
}
ImGui::End();
}
+void GPU_HW_OpenGL::UpdateSettings()
+{
+ GPU_HW::UpdateSettings();
+
+ if (m_resolution_scale != m_system->GetSettings().gpu_resolution_scale)
+ {
+ m_resolution_scale = m_system->GetSettings().gpu_resolution_scale;
+ CreateFramebuffer();
+ CompilePrograms();
+
+ m_system->GetHostInterface()->AddOSDMessage(TinyString::FromFormat("Changed internal resolution to %ux (%ux%u)",
+ m_resolution_scale, m_vram_texture->GetWidth(),
+ m_vram_texture->GetHeight()));
+ }
+}
+
void GPU_HW_OpenGL::InvalidateVRAMReadCache()
{
m_vram_read_texture_dirty = true;
@@ -357,7 +351,7 @@ void GPU_HW_OpenGL::UpdateDisplay()
const u32 texture_height = m_vram_texture->GetHeight();
// TODO: 24-bit support.
- if (m_show_vram)
+ if (m_debug_options.show_vram)
{
m_system->GetHostInterface()->SetDisplayTexture(m_vram_texture.get(), 0, 0, texture_width, texture_height, 1.0f);
}
diff --git a/src/core/gpu_hw_opengl.h b/src/core/gpu_hw_opengl.h
index 3efde427f..5869faa08 100644
--- a/src/core/gpu_hw_opengl.h
+++ b/src/core/gpu_hw_opengl.h
@@ -15,7 +15,8 @@ public:
bool Initialize(System* system, DMA* dma, InterruptController* interrupt_controller, Timers* timers) override;
void Reset() override;
- void RenderUI() override;
+ void RenderStatistics() override;
+ void UpdateSettings() override;
protected:
void UpdateDisplay() override;
@@ -73,5 +74,4 @@ private:
GLStats m_stats = {};
GLStats m_last_stats = {};
- bool m_show_vram = false;
};
diff --git a/src/core/host_interface.cpp b/src/core/host_interface.cpp
index 7330cae07..fcbec0e90 100644
--- a/src/core/host_interface.cpp
+++ b/src/core/host_interface.cpp
@@ -10,7 +10,9 @@ HostInterface::~HostInterface() = default;
bool HostInterface::InitializeSystem(const char* filename, const char* exp1_filename)
{
- m_system = std::make_unique(this);
+ Settings settings;
+
+ m_system = std::make_unique(this, settings);
if (!m_system->Initialize())
{
m_system.reset();
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
new file mode 100644
index 000000000..96aa9b689
--- /dev/null
+++ b/src/core/settings.cpp
@@ -0,0 +1,3 @@
+#include "settings.h"
+
+Settings::Settings() = default;
\ No newline at end of file
diff --git a/src/core/settings.h b/src/core/settings.h
new file mode 100644
index 000000000..4b662d32f
--- /dev/null
+++ b/src/core/settings.h
@@ -0,0 +1,18 @@
+#pragma once
+#include "types.h"
+
+enum class GPUBackend
+{
+ OpenGL
+};
+
+struct Settings
+{
+ Settings();
+
+ GPUBackend gpu_backend = GPUBackend::OpenGL;
+ u32 gpu_resolution_scale = 1;
+
+ // TODO: Controllers, memory cards, etc.
+};
+
diff --git a/src/core/system.cpp b/src/core/system.cpp
index 760ad68c0..7727378f7 100644
--- a/src/core/system.cpp
+++ b/src/core/system.cpp
@@ -15,7 +15,8 @@
#include
Log_SetChannel(System);
-System::System(HostInterface* host_interface) : m_host_interface(host_interface)
+System::System(HostInterface* host_interface, const Settings& settings)
+ : m_host_interface(host_interface), m_settings(settings)
{
m_cpu = std::make_unique();
m_bus = std::make_unique();
@@ -32,6 +33,11 @@ System::System(HostInterface* host_interface) : m_host_interface(host_interface)
System::~System() = default;
+void System::UpdateSettings()
+{
+ m_gpu->UpdateSettings();
+}
+
bool System::Initialize()
{
if (!m_cpu->Initialize(m_bus.get()))
@@ -145,11 +151,6 @@ void System::RunFrame()
}
}
-void System::RenderUI()
-{
- m_gpu->RenderUI();
-}
-
bool System::LoadEXE(const char* filename)
{
#pragma pack(push, 1)
diff --git a/src/core/system.h b/src/core/system.h
index afb5f6228..399257410 100644
--- a/src/core/system.h
+++ b/src/core/system.h
@@ -1,4 +1,5 @@
#pragma once
+#include "settings.h"
#include "types.h"
#include
@@ -7,8 +8,7 @@ class StateWrapper;
class HostInterface;
-namespace CPU
-{
+namespace CPU {
class Core;
}
@@ -26,16 +26,22 @@ class MDEC;
class System
{
public:
- System(HostInterface* host_interface);
+ System(HostInterface* host_interface, const Settings& settings);
~System();
HostInterface* GetHostInterface() const { return m_host_interface; }
+ CPU::Core* GetCPU() const { return m_cpu.get(); }
+ Bus* GetBus() const { return m_bus.get(); }
+ GPU* GetGPU() const { return m_gpu.get(); }
u32 GetFrameNumber() const { return m_frame_number; }
u32 GetInternalFrameNumber() const { return m_internal_frame_number; }
void IncrementFrameNumber() { m_frame_number++; }
void IncrementInternalFrameNumber() { m_internal_frame_number++; }
+ Settings& GetSettings() { return m_settings; }
+ void UpdateSettings();
+
bool Initialize();
void Reset();
@@ -43,7 +49,6 @@ public:
bool SaveState(ByteStream* state);
void RunFrame();
- void RenderUI();
bool LoadEXE(const char* filename);
bool SetExpansionROM(const char* filename);
@@ -74,4 +79,6 @@ private:
std::unique_ptr m_mdec;
u32 m_frame_number = 1;
u32 m_internal_frame_number = 1;
+
+ Settings m_settings;
};
diff --git a/src/duckstation/sdl_interface.cpp b/src/duckstation/sdl_interface.cpp
index af86718c8..284367af1 100644
--- a/src/duckstation/sdl_interface.cpp
+++ b/src/duckstation/sdl_interface.cpp
@@ -3,6 +3,7 @@
#include "YBaseLib/Error.h"
#include "YBaseLib/Log.h"
#include "core/digital_controller.h"
+#include "core/gpu.h"
#include "core/memory_card.h"
#include "core/system.h"
#include "icon.h"
@@ -458,7 +459,8 @@ void SDLInterface::RenderImGui()
{
RenderMainMenuBar();
- m_system->RenderUI();
+ if (m_show_gpu_statistics)
+ m_system->GetGPU()->RenderStatistics();
RenderOSDMessages();
@@ -518,6 +520,48 @@ void SDLInterface::RenderMainMenuBar()
ImGui::EndMenu();
}
+ if (ImGui::BeginMenu("Settings"))
+ {
+ if (ImGui::BeginMenu("GPU"))
+ {
+ if (ImGui::BeginMenu("Internal Resolution"))
+ {
+ const u32 current_internal_resolution = m_system->GetSettings().gpu_resolution_scale;
+ for (u32 scale = 1; scale <= 16; scale++)
+ {
+ bool selected = current_internal_resolution == scale;
+ if (ImGui::MenuItem(
+ TinyString::FromFormat("%ux (%ux%u)", scale, scale * GPU::VRAM_WIDTH, scale * GPU::VRAM_HEIGHT),
+ nullptr, &selected))
+ {
+ m_system->GetSettings().gpu_resolution_scale = scale;
+ m_system->UpdateSettings();
+ }
+ }
+
+ ImGui::EndMenu();
+ }
+
+ ImGui::EndMenu();
+ }
+
+ ImGui::EndMenu();
+ }
+
+ if (ImGui::BeginMenu("Debug"))
+ {
+ if (ImGui::BeginMenu("GPU"))
+ {
+ ImGui::MenuItem("Show Statistics", nullptr, &m_show_gpu_statistics);
+ ImGui::Separator();
+
+ m_system->GetGPU()->RenderDebugMenu();
+ ImGui::EndMenu();
+ }
+
+ ImGui::EndMenu();
+ }
+
ImGui::SetCursorPosX(ImGui::GetIO().DisplaySize.x - 170.0f);
ImGui::Text("FPS: %.2f", m_fps);
diff --git a/src/duckstation/sdl_interface.h b/src/duckstation/sdl_interface.h
index 5e3adf3f6..aebdc0a3f 100644
--- a/src/duckstation/sdl_interface.h
+++ b/src/duckstation/sdl_interface.h
@@ -87,4 +87,7 @@ private:
u32 m_last_frame_number = 0;
u32 m_last_internal_frame_number = 0;
Timer m_fps_timer;
+
+ // UI options
+ bool m_show_gpu_statistics = false;
};