From 9b56499afab0a887029aa5f1f30d0a900526fdea Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sat, 26 Oct 2019 12:55:56 +1000 Subject: [PATCH] Refactoring settings/support changing GPU renderer at runtime --- src/core/bus.h | 7 ++- src/core/cdrom.cpp | 10 +--- src/core/cdrom.h | 5 -- src/core/dma.h | 3 + src/core/gpu.cpp | 39 ++++++------- src/core/gpu.h | 95 ++++++++++++++++++++++++------- src/core/gpu_commands.cpp | 5 +- src/core/gpu_hw.cpp | 29 +++------- src/core/gpu_hw.h | 7 --- src/core/gpu_hw_opengl.cpp | 35 +++--------- src/core/gpu_hw_opengl.h | 5 +- src/core/settings.h | 23 ++++++-- src/core/spu.cpp | 13 +---- src/core/spu.h | 6 +- src/core/system.cpp | 71 +++++++++++++++-------- src/core/system.h | 15 +++-- src/core/timers.cpp | 12 +--- src/core/timers.h | 5 +- src/duckstation/sdl_interface.cpp | 83 ++++++++++++++++++++++++--- src/duckstation/sdl_interface.h | 2 + 20 files changed, 281 insertions(+), 189 deletions(-) diff --git a/src/core/bus.h b/src/core/bus.h index 24663ec9e..9d4a28123 100644 --- a/src/core/bus.h +++ b/src/core/bus.h @@ -38,7 +38,7 @@ public: bool WriteByte(PhysicalMemoryAddress address, u8 value); bool WriteHalfWord(PhysicalMemoryAddress address, u16 value); bool WriteWord(PhysicalMemoryAddress address, u32 value); - + template TickCount DispatchAccess(PhysicalMemoryAddress address, u32& value); @@ -49,6 +49,9 @@ public: void PatchBIOS(u32 address, u32 value, u32 mask = UINT32_C(0xFFFFFFFF)); void SetExpansionROM(std::vector data); + // changing interfaces + void SetGPU(GPU* gpu) { m_gpu = gpu; } + private: enum : u32 { @@ -101,7 +104,7 @@ private: enum : u32 { - RAM_ACCESS_DELAY = 6, // Nocash docs say RAM takes 6 cycles to access. + RAM_ACCESS_DELAY = 6, // Nocash docs say RAM takes 6 cycles to access. MEMCTRL_REG_COUNT = 9 }; diff --git a/src/core/cdrom.cpp b/src/core/cdrom.cpp index f6c0f4378..90dcc0e27 100644 --- a/src/core/cdrom.cpp +++ b/src/core/cdrom.cpp @@ -1178,11 +1178,8 @@ void CDROM::DrawDebugWindow() static const ImVec4 active_color{1.0f, 1.0f, 1.0f, 1.0f}; static const ImVec4 inactive_color{0.4f, 0.4f, 0.4f, 1.0f}; - if (!m_show_cdrom_state) - return; - ImGui::SetNextWindowSize(ImVec2(800, 500), ImGuiCond_FirstUseEver); - if (!ImGui::Begin("CDROM State", &m_show_cdrom_state)) + if (!ImGui::Begin("CDROM State", &m_system->GetSettings().debugging.show_cdrom_state)) { ImGui::End(); return; @@ -1320,8 +1317,3 @@ void CDROM::DrawDebugWindow() ImGui::End(); } - -void CDROM::DrawDebugMenu() -{ - ImGui::MenuItem("CDROM", nullptr, &m_show_cdrom_state); -} diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 490ae4c0f..4901ddeba 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -49,9 +49,6 @@ public: // Render statistics debug window. void DrawDebugWindow(); - // Manipulating debug options. - void DrawDebugMenu(); - private: static constexpr u32 PARAM_FIFO_SIZE = 16; static constexpr u32 RESPONSE_FIFO_SIZE = 16; @@ -226,6 +223,4 @@ private: InlineFIFOQueue m_response_fifo; HeapFIFOQueue m_data_fifo; std::vector m_sector_buffer; - - bool m_show_cdrom_state = false; }; diff --git a/src/core/dma.h b/src/core/dma.h index d201e9d16..6fa735bfe 100644 --- a/src/core/dma.h +++ b/src/core/dma.h @@ -45,6 +45,9 @@ public: void SetRequest(Channel channel, bool request); + // changing interfaces + void SetGPU(GPU* gpu) { m_gpu = gpu; } + private: static constexpr PhysicalMemoryAddress ADDRESS_MASK = UINT32_C(0x00FFFFFF); static constexpr u32 TRANSFER_TICKS = 10; diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index 0984f3c9c..e67960f08 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -2,6 +2,7 @@ #include "YBaseLib/Log.h" #include "common/state_wrapper.h" #include "dma.h" +#include "host_interface.h" #include "interrupt_controller.h" #include "stb_image_write.h" #include "system.h" @@ -25,6 +26,17 @@ bool GPU::Initialize(System* system, DMA* dma, InterruptController* interrupt_co return true; } +void GPU::UpdateResolutionScale() +{ + const u32 new_scale = std::min(m_system->GetSettings().gpu_resolution_scale, m_max_resolution_scale); + if (m_resolution_scale == new_scale) + return; + + m_resolution_scale = new_scale; + m_system->GetHostInterface()->AddOSDMessage(TinyString::FromFormat( + "Changed internal resolution to %ux (%ux%u)", m_resolution_scale, VRAM_WIDTH * new_scale, VRAM_HEIGHT * new_scale)); +} + void GPU::Reset() { SoftReset(); @@ -144,8 +156,6 @@ void GPU::ResetGraphicsAPIState() {} void GPU::RestoreGraphicsAPIState() {} -void GPU::UpdateSettings() {} - void GPU::UpdateGPUSTAT() { m_GPUSTAT.ready_to_send_vram = !m_GPUREAD_buffer.empty(); @@ -762,29 +772,10 @@ bool GPU::DumpVRAMToFile(const char* filename, u32 width, u32 height, u32 stride return (stbi_write_png(filename, width, height, 4, rgba8_buf.data(), sizeof(u32) * width) != 0); } -void GPU::DrawDebugWindows() -{ - if (m_debug_options.show_state) - DrawDebugStateWindow(); -} - -void GPU::DrawDebugMenu() -{ - if (ImGui::BeginMenu("GPU")) - { - ImGui::MenuItem("Show State", nullptr, &m_debug_options.show_state); - 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); - - ImGui::EndMenu(); - } -} - void GPU::DrawDebugStateWindow() { ImGui::SetNextWindowSize(ImVec2(450, 550), ImGuiCond_FirstUseEver); - if (!ImGui::Begin("GPU State", &m_debug_options.show_state)) + if (!ImGui::Begin("GPU State", &m_system->GetSettings().debugging.show_gpu_state)) { ImGui::End(); return; @@ -827,4 +818,8 @@ void GPU::DrawDebugStateWindow() ImGui::Text("Interrupt Request: %s", m_GPUSTAT.interrupt_request ? "Yes" : "No"); ImGui::Text("DMA Request: %s", m_GPUSTAT.dma_data_request ? "Yes" : "No"); } + + ImGui::End(); } + +void GPU::DrawRendererStatsWindow() {} diff --git a/src/core/gpu.h b/src/core/gpu.h index d14902745..8c88d1b18 100644 --- a/src/core/gpu.h +++ b/src/core/gpu.h @@ -5,6 +5,7 @@ #include #include #include +#include #include class StateWrapper; @@ -40,14 +41,10 @@ public: virtual void RestoreGraphicsAPIState(); // Render statistics debug window. - virtual void DrawDebugWindows(); - - // Manipulating debug options. - virtual void DrawDebugMenu(); - - // Called when settings change. - virtual void UpdateSettings(); + void DrawDebugStateWindow(); + virtual void DrawRendererStatsWindow(); + // MMIO access u32 ReadRegister(u32 offset); void WriteRegister(u32 offset, u32 value); @@ -55,13 +52,22 @@ public: void DMARead(u32* words, u32 word_count); void DMAWrite(const u32* words, u32 word_count); + // Resolution scaling. + u32 GetResolutionScale() const { return m_resolution_scale; } + u32 GetMaxResolutionScale() const { return m_max_resolution_scale; } + virtual void UpdateResolutionScale(); + + // Ticks for hblank/vblank. + void Execute(TickCount ticks); + // gpu_hw_opengl.cpp static std::unique_ptr CreateHardwareOpenGLRenderer(); - void Execute(TickCount ticks); - protected: // Helper/format conversion functions. + static constexpr u8 Convert5To8(u8 x5) { return (x5 << 3) | (x5 & 7); } + static constexpr u8 Convert8To5(u8 x8) { return (x8 >> 3); } + static constexpr u32 RGBA5551ToRGBA8888(u16 color) { u8 r = Truncate8(color & 31); @@ -88,6 +94,21 @@ protected: return r | (g << 5) | (b << 10) | (a << 15); } + static constexpr std::tuple UnpackTexcoord(u16 texcoord) + { + return std::make_tuple(static_cast(texcoord), static_cast(texcoord >> 8)); + } + static constexpr u16 PackTexcoord(u8 x, u8 y) { return ZeroExtend16(x) | (ZeroExtend16(y) << 8); } + + static constexpr std::tuple UnpackColorRGB24(u32 rgb24) + { + return std::make_tuple(static_cast(rgb24), static_cast(rgb24 >> 8), static_cast(rgb24 >> 16)); + } + static constexpr u32 PackColorRGB24(u8 r, u8 g, u8 b) + { + return ZeroExtend32(r) | (ZeroExtend32(g) << 8) | (ZeroExtend32(b) << 16); + } + static bool DumpVRAMToFile(const char* filename, u32 width, u32 height, u32 stride, const void* buffer, bool remove_alpha); @@ -160,12 +181,49 @@ protected: BitField y; }; - struct DebugOptions + union VRAMPixel { - bool show_state = false; - bool show_vram = false; - bool dump_cpu_to_vram_copies = false; - bool dump_vram_to_cpu_copies = false; + u16 bits; + + BitField r; + BitField g; + BitField b; + BitField c; + + u8 GetR8() const { return Convert5To8(r); } + u8 GetG8() const { return Convert5To8(g); } + u8 GetB8() const { return Convert5To8(b); } + + void Set(u8 r_, u8 g_, u8 b_, bool c_ = false) + { + bits = (ZeroExtend16(r_)) | (ZeroExtend16(g_) << 5) | (ZeroExtend16(b_) << 10) | (static_cast(c_) << 15); + } + + void ClampAndSet(u8 r_, u8 g_, u8 b_, bool c_ = false) + { + Set(std::min(r_, 0x1F), std::min(g_, 0x1F), std::min(b_, 0x1F), c_); + } + + void SetRGB24(u32 rgb24, bool c_ = false) + { + bits = Truncate16(((rgb24 >> 3) & 0x1F) | (((rgb24 >> 11) & 0x1F) << 5) | (((rgb24 >> 19) & 0x1F) << 10)) | + (static_cast(c_) << 15); + } + + void SetRGB24(u8 r8, u8 g8, u8 b8, bool c_ = false) + { + bits = (ZeroExtend16(r8 >> 3)) | (ZeroExtend16(g8 >> 3) << 5) | (ZeroExtend16(b8 >> 3) << 10) | + (static_cast(c_) << 15); + } + + u32 ToRGB24() const + { + const u32 r_ = ZeroExtend32(r.GetValue()); + const u32 g_ = ZeroExtend32(g.GetValue()); + const u32 b_ = ZeroExtend32(b.GetValue()); + + return ((r_ << 3) | (r_ & 7)) | (((g_ << 3) | (g_ & 7)) << 8) | (((b_ << 3) | (b_ & 7)) << 16); + } }; void SoftReset(); @@ -194,14 +252,15 @@ protected: virtual void DispatchRenderCommand(RenderCommand rc, u32 num_vertices, const u32* command_ptr); virtual void FlushRender(); - // Debugging - void DrawDebugStateWindow(); - System* m_system = nullptr; DMA* m_dma = nullptr; InterruptController* m_interrupt_controller = nullptr; Timers* m_timers = nullptr; + // Resolution scale. + u32 m_resolution_scale = 1; + u32 m_max_resolution_scale = 1; + union GPUSTAT { u32 bits; @@ -351,8 +410,6 @@ protected: std::vector m_GP0_buffer; std::deque m_GPUREAD_buffer; - DebugOptions m_debug_options; - private: using GP0CommandHandler = bool (GPU::*)(const u32*&, u32); using GP0CommandHandlerTable = std::array; diff --git a/src/core/gpu_commands.cpp b/src/core/gpu_commands.cpp index b9bead285..0024a95ce 100644 --- a/src/core/gpu_commands.cpp +++ b/src/core/gpu_commands.cpp @@ -2,6 +2,7 @@ #include "YBaseLib/String.h" #include "gpu.h" #include "interrupt_controller.h" +#include "system.h" Log_SetChannel(GPU); static u32 s_cpu_to_vram_dump_id = 1; @@ -291,7 +292,7 @@ bool GPU::HandleCopyRectangleCPUToVRAMCommand(const u32*& command_ptr, u32 comma return true; } - if (m_debug_options.dump_cpu_to_vram_copies) + if (m_system->GetSettings().debugging.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, &command_ptr[3], true); @@ -333,7 +334,7 @@ bool GPU::HandleCopyRectangleVRAMToCPUCommand(const u32*& command_ptr, u32 comma for (const u32 bits : temp) m_GPUREAD_buffer.push_back(bits); - if (m_debug_options.dump_vram_to_cpu_copies) + if (m_system->GetSettings().debugging.dump_vram_to_cpu_copies) { DumpVRAMToFile(SmallString::FromFormat("vram_to_cpu_copy_%u.png", s_vram_to_cpu_dump_id++), width, height, sizeof(u16) * width, temp.data(), true); diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp index 615633d9f..50150fa98 100644 --- a/src/core/gpu_hw.cpp +++ b/src/core/gpu_hw.cpp @@ -46,17 +46,9 @@ void GPU_HW::LoadVertices(RenderCommand rc, u32 num_vertices, const u32* command hw_vert.texpage = texpage; if (textured) - { hw_vert.texcoord = Truncate16(command_ptr[buffer_pos++]); - // auto [u, v] = HWVertex::DecodeTexcoord(hw_vert.texcoord); - // u = (u & (~(m_render_state.texture_window_mask_x * 8))) | ((m_render_state.texture_window_offset_x & - // m_render_state.texture_window_mask_x) * 8); v = (v & (~(m_render_state.texture_window_mask_y * 8))) | - // ((m_render_state.texture_window_offset_y & m_render_state.texture_window_mask_y) * 8); - } else - { hw_vert.texcoord = 0; - } hw_vert.padding = 0; @@ -82,8 +74,7 @@ void GPU_HW::LoadVertices(RenderCommand rc, u32 num_vertices, const u32* command const VertexPosition vp{command_ptr[buffer_pos++]}; const s32 pos_left = vp.x; const s32 pos_top = vp.y; - const auto [tex_left, tex_top] = - HWVertex::DecodeTexcoord(rc.texture_enable ? Truncate16(command_ptr[buffer_pos++]) : 0); + const auto [tex_left, tex_top] = UnpackTexcoord(rc.texture_enable ? Truncate16(command_ptr[buffer_pos++]) : 0); s32 rectangle_width; s32 rectangle_height; switch (rc.rectangle_size) @@ -112,16 +103,12 @@ void GPU_HW::LoadVertices(RenderCommand rc, u32 num_vertices, const u32* command const u8 tex_right = static_cast(tex_left + (rectangle_width - 1)); const u8 tex_bottom = static_cast(tex_top + (rectangle_height - 1)); - m_batch.vertices.push_back( - HWVertex{pos_left, pos_top, color, texpage, HWVertex::EncodeTexcoord(tex_left, tex_top)}); + m_batch.vertices.push_back(HWVertex{pos_left, pos_top, color, texpage, PackTexcoord(tex_left, tex_top)}); if (restart_strip) m_batch.vertices.push_back(m_batch.vertices.back()); - m_batch.vertices.push_back( - HWVertex{pos_right, pos_top, color, texpage, HWVertex::EncodeTexcoord(tex_right, tex_top)}); - m_batch.vertices.push_back( - HWVertex{pos_left, pos_bottom, color, texpage, HWVertex::EncodeTexcoord(tex_left, tex_bottom)}); - m_batch.vertices.push_back( - HWVertex{pos_right, pos_bottom, color, texpage, HWVertex::EncodeTexcoord(tex_right, tex_bottom)}); + m_batch.vertices.push_back(HWVertex{pos_right, pos_top, color, texpage, PackTexcoord(tex_right, tex_top)}); + m_batch.vertices.push_back(HWVertex{pos_left, pos_bottom, color, texpage, PackTexcoord(tex_left, tex_bottom)}); + m_batch.vertices.push_back(HWVertex{pos_right, pos_bottom, color, texpage, PackTexcoord(tex_right, tex_bottom)}); } break; @@ -538,9 +525,9 @@ void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices, const u32 const u32 max_added_vertices = num_vertices + 2; const bool buffer_overflow = (m_batch.vertices.size() + max_added_vertices) >= MAX_BATCH_VERTEX_COUNT; const bool rc_changed = - m_batch.render_command_bits != rc.bits && (m_batch.transparency_enable != rc_transparency_enable || - m_batch.texture_enable != rc_texture_enable || m_batch.texture_blending_enable != rc_texture_blend_enable || - m_batch.primitive != rc_primitive); + m_batch.render_command_bits != rc.bits && + (m_batch.transparency_enable != rc_transparency_enable || m_batch.texture_enable != rc_texture_enable || + m_batch.texture_blending_enable != rc_texture_blend_enable || m_batch.primitive != rc_primitive); const bool restart_line_strip = (rc_primitive == HWRenderBatch::Primitive::LineStrip); const bool needs_flush = !IsFlushed() && (m_render_state.IsTextureColorModeChanged() || m_render_state.IsTransparencyModeChanged() || diff --git a/src/core/gpu_hw.h b/src/core/gpu_hw.h index 154e2388d..0c558d8b3 100644 --- a/src/core/gpu_hw.h +++ b/src/core/gpu_hw.h @@ -22,12 +22,6 @@ protected: u32 texpage; u16 texcoord; u16 padding; - - static constexpr std::tuple DecodeTexcoord(u16 texcoord) - { - return std::make_tuple(static_cast(texcoord), static_cast(texcoord >> 8)); - } - static constexpr u16 EncodeTexcoord(u8 x, u8 y) { return ZeroExtend16(x) | (ZeroExtend16(y) << 8); } }; struct HWRenderBatch @@ -99,7 +93,6 @@ protected: std::string GenerateFillFragmentShader(); std::string GenerateDisplayFragmentShader(bool depth_24bit, bool interlaced); - u32 m_resolution_scale = 1; HWRenderBatch m_batch = {}; private: diff --git a/src/core/gpu_hw_opengl.cpp b/src/core/gpu_hw_opengl.cpp index 8918c3401..174f7e4be 100644 --- a/src/core/gpu_hw_opengl.cpp +++ b/src/core/gpu_hw_opengl.cpp @@ -65,23 +65,18 @@ void GPU_HW_OpenGL::RestoreGraphicsAPIState() glBindVertexArray(m_vao_id); } -void GPU_HW_OpenGL::DrawDebugWindows() +void GPU_HW_OpenGL::UpdateResolutionScale() { - GPU_HW::DrawDebugWindows(); + GPU_HW::UpdateResolutionScale(); - if (m_show_renderer_statistics) - DrawRendererStatistics(); + CreateFramebuffer(); + CompilePrograms(); } -void GPU_HW_OpenGL::DrawDebugMenu() +void GPU_HW_OpenGL::DrawRendererStatsWindow() { - GPU_HW::DrawDebugMenu(); + GPU_HW::DrawRendererStatsWindow(); - ImGui::MenuItem("GPU Renderer", nullptr, &m_show_renderer_statistics); -} - -void GPU_HW_OpenGL::DrawRendererStatistics() -{ ImGui::SetNextWindowSize(ImVec2(300.0f, 130.0f), ImGuiCond_FirstUseEver); const bool is_null_frame = m_stats.num_batches == 0; @@ -120,22 +115,6 @@ void GPU_HW_OpenGL::DrawRendererStatistics() 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; @@ -401,7 +380,7 @@ void GPU_HW_OpenGL::UpdateDisplay() { GPU_HW::UpdateDisplay(); - if (m_debug_options.show_vram) + if (m_system->GetSettings().debugging.show_vram) { m_system->GetHostInterface()->SetDisplayTexture(m_vram_texture.get(), 0, 0, m_vram_texture->GetWidth(), m_vram_texture->GetHeight(), 1.0f); diff --git a/src/core/gpu_hw_opengl.h b/src/core/gpu_hw_opengl.h index 1725b3a0b..c44475fd4 100644 --- a/src/core/gpu_hw_opengl.h +++ b/src/core/gpu_hw_opengl.h @@ -18,10 +18,9 @@ public: void ResetGraphicsAPIState() override; void RestoreGraphicsAPIState() override; + void UpdateResolutionScale() override; - void DrawDebugWindows() override; - void DrawDebugMenu() override; - void UpdateSettings() override; + void DrawRendererStatsWindow() override; protected: void UpdateDisplay() override; diff --git a/src/core/settings.h b/src/core/settings.h index 3d0a118c4..6a33d9c59 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -1,20 +1,33 @@ #pragma once #include "types.h" -enum class GPUBackend +enum class GPURenderer { - OpenGL + HardwareOpenGL }; struct Settings { Settings(); - GPUBackend gpu_backend = GPUBackend::OpenGL; + GPURenderer gpu_renderer = GPURenderer::HardwareOpenGL; u32 gpu_resolution_scale = 1; u32 max_gpu_resolution_scale = 1; bool gpu_vsync = true; - + + struct DebugSettings + { + bool show_gpu_state = false; + bool show_gpu_renderer_stats = false; + bool show_vram = false; + bool dump_cpu_to_vram_copies = false; + bool dump_vram_to_cpu_copies = false; + + bool show_cdrom_state = false; + bool show_spu_state = false; + bool show_timers_state = false; + bool show_mdec_state = false; + } debugging; + // TODO: Controllers, memory cards, etc. }; - diff --git a/src/core/spu.cpp b/src/core/spu.cpp index 209f359e9..db73350c6 100644 --- a/src/core/spu.cpp +++ b/src/core/spu.cpp @@ -931,16 +931,13 @@ void SPU::GenerateSample() #endif } -void SPU::DrawDebugWindow() +void SPU::DrawDebugStateWindow() { static const ImVec4 active_color{1.0f, 1.0f, 1.0f, 1.0f}; static const ImVec4 inactive_color{0.4f, 0.4f, 0.4f, 1.0f}; - if (!m_show_spu_state) - return; - ImGui::SetNextWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver); - if (!ImGui::Begin("SPU State", &m_show_spu_state)) + if (!ImGui::Begin("SPU State", &m_system->GetSettings().debugging.show_spu_state)) { ImGui::End(); return; @@ -1077,9 +1074,3 @@ void SPU::DrawDebugWindow() ImGui::End(); } - -void SPU::DrawDebugMenu() -{ - // TODO: Show RAM, etc. - ImGui::MenuItem("SPU", nullptr, &m_show_spu_state); -} diff --git a/src/core/spu.h b/src/core/spu.h index 8fd4d3f38..aa8f0b085 100644 --- a/src/core/spu.h +++ b/src/core/spu.h @@ -32,10 +32,7 @@ public: void Execute(TickCount ticks); // Render statistics debug window. - void DrawDebugWindow(); - - // Manipulating debug options. - void DrawDebugMenu(); + void DrawDebugStateWindow(); // External input from CD controller. void AddCDAudioSample(s16 left, s16 right) @@ -277,7 +274,6 @@ private: DMA* m_dma = nullptr; InterruptController* m_interrupt_controller = nullptr; AudioStream* m_audio_stream = nullptr; - bool m_show_spu_state = false; SPUCNT m_SPUCNT = {}; SPUSTAT m_SPUSTAT = {}; diff --git a/src/core/system.cpp b/src/core/system.cpp index c65a33566..ebc257f9a 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -1,4 +1,5 @@ #include "system.h" +#include "YBaseLib/AutoReleasePtr.h" #include "YBaseLib/Log.h" #include "bus.h" #include "cdrom.h" @@ -23,8 +24,6 @@ System::System(HostInterface* host_interface, const Settings& settings) m_bus = std::make_unique(); m_dma = std::make_unique(); m_interrupt_controller = std::make_unique(); - // m_gpu = std::make_unique(); - m_gpu = GPU::CreateHardwareOpenGLRenderer(); m_cdrom = std::make_unique(); m_pad = std::make_unique(); m_timers = std::make_unique(); @@ -34,9 +33,31 @@ System::System(HostInterface* host_interface, const Settings& settings) System::~System() = default; -void System::UpdateSettings() +bool System::RecreateGPU() { - m_gpu->UpdateSettings(); + // save current state + AutoReleasePtr state_stream = ByteStream_CreateGrowableMemoryStream(); + StateWrapper sw(state_stream, StateWrapper::Mode::Write); + const bool state_valid = m_gpu->DoState(sw); + if (!state_valid) + Log_ErrorPrintf("Failed to save old GPU state when switching renderers"); + + // create new renderer + m_gpu.reset(); + if (!CreateGPU()) + { + Panic("Failed to recreate GPU"); + return false; + } + + if (state_valid) + { + state_stream->SeekAbsolute(0); + sw.SetMode(StateWrapper::Mode::Read); + m_gpu->DoState(sw); + } + + return true; } bool System::Initialize() @@ -59,7 +80,7 @@ bool System::Initialize() if (!m_interrupt_controller->Initialize(m_cpu.get())) return false; - if (!m_gpu->Initialize(this, m_dma.get(), m_interrupt_controller.get(), m_timers.get())) + if (!CreateGPU()) return false; if (!m_cdrom->Initialize(this, m_dma.get(), m_interrupt_controller.get(), m_spu.get())) @@ -80,6 +101,28 @@ bool System::Initialize() return true; } +bool System::CreateGPU() +{ + switch (m_settings.gpu_renderer) + { + case GPURenderer::HardwareOpenGL: + default: + m_gpu = GPU::CreateHardwareOpenGLRenderer(); + break; + } + + if (!m_gpu || !m_gpu->Initialize(this, m_dma.get(), m_interrupt_controller.get(), m_timers.get())) + return false; + + m_bus->SetGPU(m_gpu.get()); + m_dma->SetGPU(m_gpu.get()); + + // the new GPU could have a lower maximum resolution + m_settings.gpu_resolution_scale = m_gpu->GetResolutionScale(); + m_settings.max_gpu_resolution_scale = m_gpu->GetMaxResolutionScale(); + return true; +} + bool System::DoState(StateWrapper& sw) { if (!sw.DoMarker("System")) @@ -326,21 +369,3 @@ void System::RemoveMedia() { m_cdrom->RemoveMedia(); } - -void System::DrawDebugMenus() -{ - m_gpu->DrawDebugMenu(); - m_spu->DrawDebugMenu(); - m_timers->DrawDebugMenu(); - m_cdrom->DrawDebugMenu(); - m_mdec->DrawDebugMenu(); -} - -void System::DrawDebugWindows() -{ - m_gpu->DrawDebugWindows(); - m_spu->DrawDebugWindow(); - m_timers->DrawDebugWindow(); - m_cdrom->DrawDebugWindow(); - m_mdec->DrawDebugWindow(); -} diff --git a/src/core/system.h b/src/core/system.h index 10a1645ab..24df00672 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -29,11 +29,18 @@ public: System(HostInterface* host_interface, const Settings& settings); ~System(); + // Accessing components. HostInterface* GetHostInterface() const { return m_host_interface; } CPU::Core* GetCPU() const { return m_cpu.get(); } Bus* GetBus() const { return m_bus.get(); } + DMA* GetDMA() const { return m_dma.get(); } + InterruptController* GetInterruptController() const { return m_interrupt_controller.get(); } GPU* GetGPU() const { return m_gpu.get(); } + CDROM* GetCDROM() const { return m_cdrom.get(); } + Pad* GetPad() const { return m_pad.get(); } + Timers* GetTimers() const { return m_timers.get(); } SPU* GetSPU() const { return m_spu.get(); } + MDEC* GetMDEC() const { return m_mdec.get(); } u32 GetFrameNumber() const { return m_frame_number; } u32 GetInternalFrameNumber() const { return m_internal_frame_number; } @@ -42,7 +49,6 @@ public: void IncrementInternalFrameNumber() { m_internal_frame_number++; } Settings& GetSettings() { return m_settings; } - void UpdateSettings(); bool Initialize(); void Reset(); @@ -50,6 +56,9 @@ public: bool LoadState(ByteStream* state); bool SaveState(ByteStream* state); + /// Recreates the GPU component, saving/loading the state so it is preserved. Call when the GPU renderer changes. + bool RecreateGPU(); + void RunFrame(); bool LoadEXE(const char* filename); @@ -68,11 +77,9 @@ public: bool InsertMedia(const char* path); void RemoveMedia(); - void DrawDebugMenus(); - void DrawDebugWindows(); - private: bool DoState(StateWrapper& sw); + bool CreateGPU(); HostInterface* m_host_interface; std::unique_ptr m_cpu; diff --git a/src/core/timers.cpp b/src/core/timers.cpp index 1c01bf984..30ab6cfbf 100644 --- a/src/core/timers.cpp +++ b/src/core/timers.cpp @@ -292,16 +292,8 @@ void Timers::UpdateDowncount() m_system->SetDowncount(min_ticks); } -void Timers::DrawDebugMenu() +void Timers::DrawDebugStateWindow() { - ImGui::MenuItem("Timers", nullptr, &m_debug_show_state); -} - -void Timers::DrawDebugWindow() -{ - if (!m_debug_show_state) - return; - static constexpr u32 NUM_COLUMNS = 10; static constexpr std::array column_names = { {"#", "Value", "Target", "Sync", "Reset", "IRQ", "IRQRepeat", "IRQToggle", "Clock Source", "Reached"}}; @@ -313,7 +305,7 @@ void Timers::DrawDebugWindow() {{"SysClk", "DotClk", "SysClk/8", "SysClk/8"}}}}; ImGui::SetNextWindowSize(ImVec2(800, 100), ImGuiCond_FirstUseEver); - if (!ImGui::Begin("Timer State", &m_debug_show_state)) + if (!ImGui::Begin("Timer State", &m_system->GetSettings().debugging.show_timers_state)) { ImGui::End(); return; diff --git a/src/core/timers.h b/src/core/timers.h index 1e6e14034..df6fb1543 100644 --- a/src/core/timers.h +++ b/src/core/timers.h @@ -20,8 +20,7 @@ public: void SetGate(u32 timer, bool state); - void DrawDebugMenu(); - void DrawDebugWindow(); + void DrawDebugStateWindow(); // dot clock/hblank/sysclk div 8 bool IsUsingExternalClock(u32 timer) const { return m_states[timer].external_counting_enabled; } @@ -81,6 +80,4 @@ private: std::array m_states{}; u32 m_sysclk_div_8_carry = 0; // partial ticks for timer 3 with sysclk/8 - - bool m_debug_show_state = false; }; diff --git a/src/duckstation/sdl_interface.cpp b/src/duckstation/sdl_interface.cpp index d54649984..52946d0ce 100644 --- a/src/duckstation/sdl_interface.cpp +++ b/src/duckstation/sdl_interface.cpp @@ -2,10 +2,15 @@ #include "YBaseLib/ByteStream.h" #include "YBaseLib/Error.h" #include "YBaseLib/Log.h" +#include "core/cdrom.h" #include "core/digital_controller.h" +#include "core/dma.h" #include "core/gpu.h" +#include "core/mdec.h" #include "core/memory_card.h" +#include "core/spu.h" #include "core/system.h" +#include "core/timers.h" #include "icon.h" #include "sdl_audio_stream.h" #include @@ -16,6 +21,9 @@ #include Log_SetChannel(SDLInterface); +static constexpr std::array, 1> s_gpu_renderer_names = { + {{GPURenderer::HardwareOpenGL, "Hardware (OpenGL)"}}}; + SDLInterface::SDLInterface() = default; SDLInterface::~SDLInterface() @@ -699,7 +707,7 @@ void SDLInterface::DrawImGui() DrawMainMenuBar(); if (m_system) - m_system->DrawDebugWindows(); + DrawDebugWindows(); else DrawPoweredOffWindow(); @@ -777,6 +785,21 @@ void SDLInterface::DrawMainMenuBar() if (ImGui::BeginMenu("GPU", system_enabled)) { + if (ImGui::BeginMenu("Renderer")) + { + const GPURenderer current = m_system->GetSettings().gpu_renderer; + for (const auto& it : s_gpu_renderer_names) + { + if (ImGui::MenuItem(it.second, nullptr, current == it.first)) + { + m_system->GetSettings().gpu_renderer = it.first; + m_system->RecreateGPU(); + } + } + + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("Internal Resolution")) { const u32 current_internal_resolution = m_system->GetSettings().gpu_resolution_scale; @@ -787,7 +810,7 @@ void SDLInterface::DrawMainMenuBar() nullptr, current_internal_resolution == scale)) { m_system->GetSettings().gpu_resolution_scale = scale; - m_system->UpdateSettings(); + m_system->GetGPU()->UpdateResolutionScale(); } } @@ -804,13 +827,7 @@ void SDLInterface::DrawMainMenuBar() } if (m_system) - { - if (ImGui::BeginMenu("Debug")) - { - m_system->DrawDebugMenus(); - ImGui::EndMenu(); - } - } + DrawDebugMenu(); if (ImGui::BeginMenu("Help")) { @@ -955,6 +972,54 @@ void SDLInterface::DrawAboutWindow() ImGui::End(); } +void SDLInterface::DrawDebugMenu() +{ + if (!ImGui::BeginMenu("Debug", m_system != nullptr)) + return; + + Settings::DebugSettings& debug_settings = m_system->GetSettings().debugging; + + ImGui::MenuItem("Show System State"); + ImGui::Separator(); + + ImGui::MenuItem("Show GPU State", nullptr, &debug_settings.show_gpu_state); + ImGui::MenuItem("Show GPU Renderer Stats", nullptr, &debug_settings.show_gpu_renderer_stats); + ImGui::MenuItem("Show VRAM", nullptr, &debug_settings.show_vram); + ImGui::MenuItem("Dump CPU to VRAM Copies", nullptr, &debug_settings.dump_cpu_to_vram_copies); + ImGui::MenuItem("Dump VRAM to CPU Copies", nullptr, &debug_settings.dump_vram_to_cpu_copies); + ImGui::Separator(); + + ImGui::MenuItem("Show CDROM State", nullptr, &debug_settings.show_cdrom_state); + ImGui::Separator(); + + ImGui::MenuItem("Show SPU State", nullptr, &debug_settings.show_spu_state); + ImGui::Separator(); + + ImGui::MenuItem("Show Timers State", nullptr, &debug_settings.show_timers_state); + ImGui::Separator(); + + ImGui::MenuItem("Show MDEC State", nullptr, &debug_settings.show_mdec_state); + ImGui::Separator(); + + ImGui::EndMenu(); +} + +void SDLInterface::DrawDebugWindows() +{ + const Settings::DebugSettings& debug_settings = m_system->GetSettings().debugging; + + if (debug_settings.show_gpu_state) + m_system->GetGPU()->DrawDebugStateWindow(); + if (debug_settings.show_gpu_renderer_stats) + m_system->GetGPU()->DrawRendererStatsWindow(); + if (debug_settings.show_cdrom_state) + m_system->GetCDROM()->DrawDebugWindow(); + if (debug_settings.show_timers_state) + m_system->GetTimers()->DrawDebugStateWindow(); + if (debug_settings.show_spu_state) + m_system->GetSPU()->DrawDebugStateWindow(); +} + void SDLInterface::AddOSDMessage(const char* message, float duration /*= 2.0f*/) { OSDMessage msg; diff --git a/src/duckstation/sdl_interface.h b/src/duckstation/sdl_interface.h index 6d4bd68c6..a5fb98b44 100644 --- a/src/duckstation/sdl_interface.h +++ b/src/duckstation/sdl_interface.h @@ -82,6 +82,8 @@ private: void DrawPoweredOffWindow(); void DrawAboutWindow(); void DrawOSDMessages(); + void DrawDebugMenu(); + void DrawDebugWindows(); SDL_Window* m_window = nullptr; SDL_GLContext m_gl_context = nullptr;