Refactoring settings/support changing GPU renderer at runtime

This commit is contained in:
Connor McLaughlin 2019-10-26 12:55:56 +10:00
parent ca48b21ffc
commit 9b56499afa
20 changed files with 281 additions and 189 deletions

View File

@ -38,7 +38,7 @@ public:
bool WriteByte(PhysicalMemoryAddress address, u8 value);
bool WriteHalfWord(PhysicalMemoryAddress address, u16 value);
bool WriteWord(PhysicalMemoryAddress address, u32 value);
template<MemoryAccessType type, MemoryAccessSize size>
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<u8> 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
};

View File

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

View File

@ -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<u8, RESPONSE_FIFO_SIZE> m_response_fifo;
HeapFIFOQueue<u8, DATA_FIFO_SIZE> m_data_fifo;
std::vector<u8> m_sector_buffer;
bool m_show_cdrom_state = false;
};

View File

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

View File

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

View File

@ -5,6 +5,7 @@
#include <array>
#include <deque>
#include <memory>
#include <tuple>
#include <vector>
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<GPU> 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<u8, u8> UnpackTexcoord(u16 texcoord)
{
return std::make_tuple(static_cast<u8>(texcoord), static_cast<u8>(texcoord >> 8));
}
static constexpr u16 PackTexcoord(u8 x, u8 y) { return ZeroExtend16(x) | (ZeroExtend16(y) << 8); }
static constexpr std::tuple<u8, u8, u8> UnpackColorRGB24(u32 rgb24)
{
return std::make_tuple(static_cast<u8>(rgb24), static_cast<u8>(rgb24 >> 8), static_cast<u8>(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<u32, s32, 16, 12> 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<u16, u8, 0, 5> r;
BitField<u16, u8, 5, 5> g;
BitField<u16, u8, 10, 5> b;
BitField<u16, bool, 15, 1> 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<u16>(c_) << 15);
}
void ClampAndSet(u8 r_, u8 g_, u8 b_, bool c_ = false)
{
Set(std::min<u8>(r_, 0x1F), std::min<u8>(g_, 0x1F), std::min<u8>(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<u16>(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<u16>(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<u32> m_GP0_buffer;
std::deque<u32> m_GPUREAD_buffer;
DebugOptions m_debug_options;
private:
using GP0CommandHandler = bool (GPU::*)(const u32*&, u32);
using GP0CommandHandlerTable = std::array<GP0CommandHandler, 256>;

View File

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

View File

@ -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<u8>(tex_left + (rectangle_width - 1));
const u8 tex_bottom = static_cast<u8>(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() ||

View File

@ -22,12 +22,6 @@ protected:
u32 texpage;
u16 texcoord;
u16 padding;
static constexpr std::tuple<u8, u8> DecodeTexcoord(u16 texcoord)
{
return std::make_tuple(static_cast<u8>(texcoord), static_cast<u8>(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:

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<Bus>();
m_dma = std::make_unique<DMA>();
m_interrupt_controller = std::make_unique<InterruptController>();
// m_gpu = std::make_unique<GPU>();
m_gpu = GPU::CreateHardwareOpenGLRenderer();
m_cdrom = std::make_unique<CDROM>();
m_pad = std::make_unique<Pad>();
m_timers = std::make_unique<Timers>();
@ -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<ByteStream> 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();
}

View File

@ -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<CPU::Core> m_cpu;

View File

@ -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<const char*, NUM_COLUMNS> 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;

View File

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

@ -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 <cinttypes>
@ -16,6 +21,9 @@
#include <nfd.h>
Log_SetChannel(SDLInterface);
static constexpr std::array<std::pair<GPURenderer, const char*>, 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;

View File

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