mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-26 15:45:42 +00:00
Refactoring settings/support changing GPU renderer at runtime
This commit is contained in:
parent
ca48b21ffc
commit
9b56499afa
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() ||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 = {};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue