diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index 2194dc3f3..0169b3411 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -143,15 +143,6 @@ void GPU::ResetGraphicsAPIState() {} void GPU::RestoreGraphicsAPIState() {} -void GPU::DrawStatistics() {} - -void GPU::DrawDebugMenu() -{ - 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() @@ -976,3 +967,70 @@ 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)) + { + ImGui::End(); + return; + } + + if (ImGui::CollapsingHeader("CRTC", ImGuiTreeNodeFlags_DefaultOpen)) + { + const auto& cs = m_crtc_state; + ImGui::Text("Resolution: %ux%u", cs.horizontal_resolution, cs.vertical_resolution); + ImGui::Text("Dot Clock Divider: %u", cs.dot_clock_divider); + ImGui::Text("Vertical Interlace: %s (%s field)", m_GPUSTAT.vertical_interlace ? "Yes" : "No", + m_GPUSTAT.interlaced_field ? "odd" : "even"); + ImGui::Text("Display Enable: %s", m_GPUSTAT.display_enable ? "Yes" : "No"); + ImGui::Text("Drawing Even Line: %s", m_GPUSTAT.drawing_even_line ? "Yes" : "No"); + ImGui::NewLine(); + + ImGui::Text("Color Depth: %u-bit", m_GPUSTAT.display_area_color_depth_24 ? 24 : 15); + ImGui::Text("Start Offset: (%u, %u)", cs.regs.X.GetValue(), cs.regs.Y.GetValue()); + ImGui::Text("Display Range: %u-%u, %u-%u", cs.regs.X1.GetValue(), cs.regs.X2.GetValue(), cs.regs.Y1.GetValue(), + cs.regs.Y2.GetValue()); + ImGui::NewLine(); + + ImGui::Text("Visible Resolution: %ux%u", cs.visible_horizontal_resolution, cs.visible_vertical_resolution); + ImGui::Text("Ticks Per Scanline: %u (%u visible)", cs.ticks_per_scanline, cs.visible_ticks_per_scanline); + ImGui::Text("Scanlines Per Frame: %u", cs.total_scanlines_per_frame); + ImGui::Text("Current Scanline: %u (tick %u)", cs.current_scanline, cs.current_tick_in_scanline); + ImGui::Text("Horizontal Blank: %s", cs.in_hblank ? "Yes" : "No"); + ImGui::Text("Vertical Blank: %s", cs.in_vblank ? "Yes" : "No"); + } + + if (ImGui::CollapsingHeader("GPU", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::Text("Dither: %s", m_GPUSTAT.dither_enable ? "Enabled" : "Disabled"); + ImGui::Text("Draw To Display Area: %s", m_GPUSTAT.dither_enable ? "Yes" : "No"); + ImGui::Text("Draw Set Mask Bit: %s", m_GPUSTAT.draw_set_mask_bit ? "Yes" : "No"); + ImGui::Text("Draw To Masked Pixels: %s", m_GPUSTAT.draw_to_masked_pixels ? "Yes" : "No"); + ImGui::Text("Reverse Flag: %s", m_GPUSTAT.reverse_flag ? "Yes" : "No"); + ImGui::Text("Texture Disable: %s", m_GPUSTAT.texture_disable ? "Yes" : "No"); + ImGui::Text("PAL Mode: %s", m_GPUSTAT.pal_mode ? "Yes" : "No"); + ImGui::Text("Interrupt Request: %s", m_GPUSTAT.interrupt_request ? "Yes" : "No"); + ImGui::Text("DMA Request: %s", m_GPUSTAT.dma_data_request ? "Yes" : "No"); + } +} \ No newline at end of file diff --git a/src/core/gpu.h b/src/core/gpu.h index 4e38e35d8..48017adfa 100644 --- a/src/core/gpu.h +++ b/src/core/gpu.h @@ -40,7 +40,7 @@ public: virtual void RestoreGraphicsAPIState(); // Render statistics debug window. - virtual void DrawStatistics(); + virtual void DrawDebugWindows(); // Manipulating debug options. virtual void DrawDebugMenu(); @@ -162,9 +162,10 @@ protected: struct DebugOptions { - bool show_vram; - bool dump_cpu_to_vram_copies; - bool dump_vram_to_cpu_copies; + bool show_state = false; + bool show_vram = false; + bool dump_cpu_to_vram_copies = false; + bool dump_vram_to_cpu_copies = false; }; void SoftReset(); @@ -200,6 +201,9 @@ protected: virtual void DispatchRenderCommand(RenderCommand rc, u32 num_vertices); virtual void FlushRender(); + // Debugging + void DrawDebugStateWindow(); + System* m_system = nullptr; DMA* m_dma = nullptr; InterruptController* m_interrupt_controller = nullptr; @@ -351,5 +355,5 @@ protected: std::vector m_GP0_command; std::deque m_GPUREAD_buffer; - DebugOptions m_debug_options = {}; + DebugOptions m_debug_options; }; diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp index 18f5e9a6a..b8fda68b4 100644 --- a/src/core/gpu_hw.cpp +++ b/src/core/gpu_hw.cpp @@ -587,5 +587,4 @@ void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices) } LoadVertices(rc, num_vertices); - FlushRender(); } diff --git a/src/core/gpu_hw_opengl.cpp b/src/core/gpu_hw_opengl.cpp index 87593ea3f..39b2b4230 100644 --- a/src/core/gpu_hw_opengl.cpp +++ b/src/core/gpu_hw_opengl.cpp @@ -65,11 +65,24 @@ void GPU_HW_OpenGL::RestoreGraphicsAPIState() glBindVertexArray(m_vao_id); } -void GPU_HW_OpenGL::DrawStatistics() +void GPU_HW_OpenGL::DrawDebugWindows() { - GPU_HW::DrawStatistics(); + GPU_HW::DrawDebugWindows(); - ImGui::SetNextWindowSize(ImVec2(300.0f, 130.0f), ImGuiCond_Once); + if (m_show_renderer_statistics) + DrawRendererStatistics(); +} + +void GPU_HW_OpenGL::DrawDebugMenu() +{ + GPU_HW::DrawDebugMenu(); + + 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; if (!is_null_frame) @@ -78,7 +91,7 @@ void GPU_HW_OpenGL::DrawStatistics() m_stats = {}; } - if (ImGui::Begin("GPU Render Statistics")) + if (ImGui::Begin("GPU Renderer Statistics", &m_show_renderer_statistics)) { ImGui::Columns(2); ImGui::SetColumnWidth(0, 200.0f); diff --git a/src/core/gpu_hw_opengl.h b/src/core/gpu_hw_opengl.h index d48745d05..531f508bb 100644 --- a/src/core/gpu_hw_opengl.h +++ b/src/core/gpu_hw_opengl.h @@ -19,7 +19,8 @@ public: void ResetGraphicsAPIState() override; void RestoreGraphicsAPIState() override; - void DrawStatistics() override; + void DrawDebugWindows() override; + void DrawDebugMenu() override; void UpdateSettings() override; protected: @@ -40,6 +41,8 @@ private: u32 num_vertices; }; + void DrawRendererStatistics(); + std::tuple ConvertToFramebufferCoordinates(s32 x, s32 y); void SetMaxResolutionScale(); @@ -72,6 +75,7 @@ private: bool m_vram_read_texture_dirty = true; bool m_drawing_area_changed = true; + bool m_show_renderer_statistics = false; std::array, 3>, 2>, 4> m_render_programs; GL::Program m_reinterpret_rgb8_program; diff --git a/src/core/spu.cpp b/src/core/spu.cpp index b45f13c22..0d599ecc7 100644 --- a/src/core/spu.cpp +++ b/src/core/spu.cpp @@ -897,5 +897,5 @@ void SPU::DrawDebugWindow() void SPU::DrawDebugMenu() { // TODO: Show RAM, etc. - ImGui::MenuItem("Show State", nullptr, &m_show_spu_state); + ImGui::MenuItem("SPU", nullptr, &m_show_spu_state); } diff --git a/src/core/system.cpp b/src/core/system.cpp index 10072f5de..bc8f89e3e 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -13,6 +13,7 @@ #include "spu.h" #include "timers.h" #include +#include Log_SetChannel(System); System::System(HostInterface* host_interface, const Settings& settings) @@ -320,3 +321,17 @@ void System::RemoveMedia() { m_cdrom->RemoveMedia(); } + +void System::DrawDebugMenus() +{ + m_gpu->DrawDebugMenu(); + m_spu->DrawDebugMenu(); + m_timers->DrawDebugMenu(); +} + +void System::DrawDebugWindows() +{ + m_gpu->DrawDebugWindows(); + m_spu->DrawDebugWindow(); + m_timers->DrawDebugWindow(); +} diff --git a/src/core/system.h b/src/core/system.h index b0f5fed48..6d6752747 100644 --- a/src/core/system.h +++ b/src/core/system.h @@ -65,6 +65,9 @@ public: bool InsertMedia(const char* path); void RemoveMedia(); + void DrawDebugMenus(); + void DrawDebugWindows(); + private: bool DoState(StateWrapper& sw); diff --git a/src/core/timers.cpp b/src/core/timers.cpp index 86429edce..0531773da 100644 --- a/src/core/timers.cpp +++ b/src/core/timers.cpp @@ -3,6 +3,7 @@ #include "common/state_wrapper.h" #include "interrupt_controller.h" #include "system.h" +#include Log_SetChannel(Timers); Timers::Timers() = default; @@ -140,7 +141,7 @@ void Timers::Execute(TickCount sysclk_ticks) } else if (m_states[2].counting_enabled) { - AddTicks(2, m_states[2].external_counting_enabled ? sysclk_ticks / 8 : sysclk_ticks); + AddTicks(2, sysclk_ticks); } UpdateDowncount(); @@ -290,3 +291,81 @@ void Timers::UpdateDowncount() m_system->SetDowncount(min_ticks); } + +void Timers::DrawDebugMenu() +{ + 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"}}; + static constexpr std::array sync_mode_names = { + {"PauseOnGate", "ResetOnGate", "ResetAndRunOnGate", "FreeRunOnGate"}}; + static constexpr std::array, 3> clock_source_names = { + {{{"SysClk", "DotClk", "SysClk", "DotClk"}}, + {{"SysClk", "HBlank", "SysClk", "HBlank"}}, + {{"SysClk", "DotClk", "SysClk/8", "SysClk/8"}}}}; + + ImGui::SetNextWindowSize(ImVec2(800, 100), ImGuiCond_FirstUseEver); + if (!ImGui::Begin("Timer State", &m_debug_show_state)) + { + ImGui::End(); + return; + } + + ImGui::Columns(NUM_COLUMNS); + ImGui::SetColumnWidth(0, 20.0f); + ImGui::SetColumnWidth(1, 50.0f); + ImGui::SetColumnWidth(2, 50.0f); + ImGui::SetColumnWidth(3, 100.0f); + ImGui::SetColumnWidth(4, 80.0f); + ImGui::SetColumnWidth(5, 80.0f); + ImGui::SetColumnWidth(6, 80.0f); + ImGui::SetColumnWidth(7, 80.0f); + ImGui::SetColumnWidth(8, 80.0f); + ImGui::SetColumnWidth(9, 80.0f); + + for (const char* title : column_names) + { + ImGui::TextUnformatted(title); + ImGui::NextColumn(); + } + + for (u32 i = 0; i < NUM_TIMERS; i++) + { + const CounterState& cs = m_states[i]; + ImGui::PushStyleColor(ImGuiCol_Text, + cs.counting_enabled ? ImVec4(1.0f, 1.0f, 1.0f, 1.0f) : ImVec4(0.5f, 0.5f, 0.5f, 1.0f)); + ImGui::Text("%u", i); + ImGui::NextColumn(); + ImGui::Text("%u", cs.counter); + ImGui::NextColumn(); + ImGui::Text("%u", cs.target); + ImGui::NextColumn(); + ImGui::Text("%s", + cs.mode.sync_enable ? sync_mode_names[static_cast(cs.mode.sync_mode.GetValue())] : "Disabled"); + ImGui::NextColumn(); + ImGui::Text("%s", cs.mode.reset_at_target ? "@Target" : "@Overflow"); + ImGui::NextColumn(); + ImGui::Text("%s%s", cs.mode.irq_at_target ? "Target " : "", cs.mode.irq_on_overflow ? "Overflow" : ""); + ImGui::NextColumn(); + ImGui::Text("%s", cs.mode.irq_repeat ? "Yes" : "No"); + ImGui::NextColumn(); + ImGui::Text("%s", cs.mode.irq_pulse_n ? "Yes" : "No"); + ImGui::NextColumn(); + ImGui::Text("%s%s", clock_source_names[i][cs.mode.clock_source], cs.external_counting_enabled ? " (External)" : ""); + ImGui::NextColumn(); + ImGui::Text("%s", cs.mode.reached_target ? "Target " : "", cs.mode.reached_overflow ? "Overflow" : ""); + ImGui::NextColumn(); + ImGui::PopStyleColor(); + } + + ImGui::Columns(1); + ImGui::End(); +} diff --git a/src/core/timers.h b/src/core/timers.h index dbce67cde..1e6e14034 100644 --- a/src/core/timers.h +++ b/src/core/timers.h @@ -20,6 +20,9 @@ public: void SetGate(u32 timer, bool state); + void DrawDebugMenu(); + void DrawDebugWindow(); + // dot clock/hblank/sysclk div 8 bool IsUsingExternalClock(u32 timer) const { return m_states[timer].external_counting_enabled; } void AddTicks(u32 timer, TickCount ticks); @@ -78,4 +81,6 @@ 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 d0c2370ee..dc3ef3cdc 100644 --- a/src/duckstation/sdl_interface.cpp +++ b/src/duckstation/sdl_interface.cpp @@ -5,7 +5,6 @@ #include "core/digital_controller.h" #include "core/gpu.h" #include "core/memory_card.h" -#include "core/spu.h" #include "core/system.h" #include "icon.h" #include "sdl_audio_stream.h" @@ -496,10 +495,7 @@ void SDLInterface::DrawImGui() { DrawMainMenuBar(); - if (m_show_gpu_statistics) - m_system->GetGPU()->DrawStatistics(); - - m_system->GetSPU()->DrawDebugWindow(); + m_system->DrawDebugWindows(); DrawOSDMessages(); @@ -585,22 +581,7 @@ void SDLInterface::DrawMainMenuBar() if (ImGui::BeginMenu("Debug")) { - if (ImGui::BeginMenu("GPU")) - { - ImGui::MenuItem("Show Statistics", nullptr, &m_show_gpu_statistics); - ImGui::Separator(); - - m_system->GetGPU()->DrawDebugMenu(); - ImGui::EndMenu(); - } - - if (ImGui::BeginMenu("SPU")) - { - m_system->GetSPU()->DrawDebugMenu(); - - ImGui::EndMenu(); - } - + m_system->DrawDebugMenus(); ImGui::EndMenu(); } diff --git a/src/duckstation/sdl_interface.h b/src/duckstation/sdl_interface.h index 855eb174a..c3eabbd52 100644 --- a/src/duckstation/sdl_interface.h +++ b/src/duckstation/sdl_interface.h @@ -92,7 +92,4 @@ private: u32 m_last_internal_frame_number = 0; u32 m_last_global_tick_counter = 0; Timer m_fps_timer; - - // UI options - bool m_show_gpu_statistics = false; };