Add debugging for GPU/Timers

This commit is contained in:
Connor McLaughlin 2019-10-12 22:15:38 +10:00
parent b945d10b04
commit 0f68c8c5d3
12 changed files with 204 additions and 46 deletions

View file

@ -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");
}
}

View file

@ -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<u32> m_GP0_command;
std::deque<u32> m_GPUREAD_buffer;
DebugOptions m_debug_options = {};
DebugOptions m_debug_options;
};

View file

@ -587,5 +587,4 @@ void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices)
}
LoadVertices(rc, num_vertices);
FlushRender();
}

View file

@ -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);

View file

@ -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<s32, s32> 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<std::array<std::array<std::array<GL::Program, 2>, 3>, 2>, 4> m_render_programs;
GL::Program m_reinterpret_rgb8_program;

View file

@ -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);
}

View file

@ -13,6 +13,7 @@
#include "spu.h"
#include "timers.h"
#include <cstdio>
#include <imgui.h>
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();
}

View file

@ -65,6 +65,9 @@ public:
bool InsertMedia(const char* path);
void RemoveMedia();
void DrawDebugMenus();
void DrawDebugWindows();
private:
bool DoState(StateWrapper& sw);

View file

@ -3,6 +3,7 @@
#include "common/state_wrapper.h"
#include "interrupt_controller.h"
#include "system.h"
#include <imgui.h>
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<const char*, NUM_COLUMNS> column_names = {
{"#", "Value", "Target", "Sync", "Reset", "IRQ", "IRQRepeat", "IRQToggle", "Clock Source", "Reached"}};
static constexpr std::array<const char*, 4> sync_mode_names = {
{"PauseOnGate", "ResetOnGate", "ResetAndRunOnGate", "FreeRunOnGate"}};
static constexpr std::array<std::array<const char*, 4>, 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<u8>(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();
}

View file

@ -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<CounterState, NUM_TIMERS> m_states{};
u32 m_sysclk_div_8_carry = 0; // partial ticks for timer 3 with sysclk/8
bool m_debug_show_state = false;
};

View file

@ -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();
}

View file

@ -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;
};