Clean up the 3D renderer for enhanced flexibility (#1895)

* Give `GPU2D::Unit` a virtual destructor

- Undefined behavior avoided!

* Add an `array2d` alias

* Move various parts of `GPU2D::SoftRenderer` to `constexpr`

- `SoftRenderer::MosaicTable` is now initialized at compile-time
- Most of the `SoftRenderer::Color*` functions are now `constexpr`
- The aforementioned functions are used with a constant value in at least one place, so they'll be at least partially computed at compile-time

* Generalize `GLRenderer::PrepareCaptureFrame`

- Declare it in the base `Renderer3D` class, but make it empty

* Remove unneeded `virtual` specifiers

* Store `Framebuffer`'s memory in `unique_ptr`s

- Reduce the risk of leaks this way

* Clean up how `GLCompositor` is initialized

- Return it as an `std::optional` instead of a `std::unique_ptr`
- Make `GLCompositor` movable
- Replace `GLCompositor`'s plain arrays with `std::array` to simplify moving

* Pass `GPU` to `GLCompositor`'s important functions instead of passing it to the constructor

* Move `GLCompositor` to be a field within `GLRenderer`

- Some methods were moved up and made `virtual`

* Fix some linker errors

* Set the renderer in the frontend

* Remove unneeded `virtual` specifiers

* Remove `RenderSettings` in favor of just exposing the relevant member variables

* Update the frontend to accommodate the core changes

* Add `constexpr` and `const` to places in the interpolator

* Qualify references to `size_t`

* Construct the `optional` directly instead of using `make_optional`

- It makes the Linux build choke
- I think it's because `GLCompositor`'s constructor is `private`
This commit is contained in:
Jesse Talavera-Greenberg
2023-11-29 09:23:11 -05:00
committed by GitHub
parent e973236203
commit 7caddf9615
15 changed files with 366 additions and 334 deletions

View File

@ -24,7 +24,6 @@
#include "GPU2D_Soft.h"
#include "GPU3D_Soft.h"
#include "GPU3D_OpenGL.h"
namespace melonDS
{
@ -64,33 +63,24 @@ enum
VRAMDirty need to be reset for the respective VRAM bank.
*/
GPU::GPU(melonDS::NDS& nds) noexcept : NDS(nds), GPU2D_A(0, *this), GPU2D_B(1, *this), GPU3D(nds)
GPU::GPU(melonDS::NDS& nds, std::unique_ptr<Renderer3D>&& renderer3d, std::unique_ptr<GPU2D::Renderer2D>&& renderer2d) noexcept :
NDS(nds),
GPU2D_A(0, *this),
GPU2D_B(1, *this),
GPU3D(nds, renderer3d ? std::move(renderer3d) : std::make_unique<SoftRenderer>(*this)),
GPU2D_Renderer(renderer2d ? std::move(renderer2d) : std::make_unique<GPU2D::SoftRenderer>(*this))
{
NDS.RegisterEventFunc(Event_LCD, LCD_StartHBlank, MemberEventFunc(GPU, StartHBlank));
NDS.RegisterEventFunc(Event_LCD, LCD_StartScanline, MemberEventFunc(GPU, StartScanline));
NDS.RegisterEventFunc(Event_LCD, LCD_FinishFrame, MemberEventFunc(GPU, FinishFrame));
NDS.RegisterEventFunc(Event_DisplayFIFO, 0, MemberEventFunc(GPU, DisplayFIFO));
GPU2D_Renderer = std::make_unique<GPU2D::SoftRenderer>(*this);
FrontBuffer = 0;
Framebuffer[0][0] = NULL; Framebuffer[0][1] = NULL;
Framebuffer[1][0] = NULL; Framebuffer[1][1] = NULL;
Renderer = 0;
}
GPU::~GPU() noexcept
{
// All unique_ptr fields are automatically cleaned up
if (Framebuffer[0][0]) delete[] Framebuffer[0][0];
if (Framebuffer[0][1]) delete[] Framebuffer[0][1];
if (Framebuffer[1][0]) delete[] Framebuffer[1][0];
if (Framebuffer[1][1]) delete[] Framebuffer[1][1];
Framebuffer[0][0] = nullptr;
Framebuffer[0][1] = nullptr;
Framebuffer[1][0] = nullptr;
Framebuffer[1][1] = nullptr;
NDS.UnregisterEventFunc(Event_LCD, LCD_StartHBlank);
NDS.UnregisterEventFunc(Event_LCD, LCD_StartScanline);
@ -198,9 +188,7 @@ void GPU::Reset() noexcept
GPU3D.Reset();
int backbuf = FrontBuffer ? 0 : 1;
GPU2D_Renderer->SetFramebuffer(Framebuffer[backbuf][1], Framebuffer[backbuf][0]);
ResetRenderer();
GPU2D_Renderer->SetFramebuffer(Framebuffer[backbuf][1].get(), Framebuffer[backbuf][0].get());
ResetVRAMCache();
@ -216,17 +204,12 @@ void GPU::Stop() noexcept
else
fbsize = 256 * 192;
memset(Framebuffer[0][0], 0, fbsize*4);
memset(Framebuffer[0][1], 0, fbsize*4);
memset(Framebuffer[1][0], 0, fbsize*4);
memset(Framebuffer[1][1], 0, fbsize*4);
memset(Framebuffer[0][0].get(), 0, fbsize*4);
memset(Framebuffer[0][1].get(), 0, fbsize*4);
memset(Framebuffer[1][0].get(), 0, fbsize*4);
memset(Framebuffer[1][1].get(), 0, fbsize*4);
#ifdef OGLRENDERER_ENABLED
// This needs a better way to know that we're
// using the OpenGL renderer specifically
if (GPU3D.IsRendererAccelerated())
CurGLCompositor->Stop();
#endif
GPU3D.Stop();
}
void GPU::DoSavestate(Savestate* file) noexcept
@ -300,78 +283,20 @@ void GPU::AssignFramebuffers() noexcept
int backbuf = FrontBuffer ? 0 : 1;
if (NDS.PowerControl9 & (1<<15))
{
GPU2D_Renderer->SetFramebuffer(Framebuffer[backbuf][0], Framebuffer[backbuf][1]);
GPU2D_Renderer->SetFramebuffer(Framebuffer[backbuf][0].get(), Framebuffer[backbuf][1].get());
}
else
{
GPU2D_Renderer->SetFramebuffer(Framebuffer[backbuf][1], Framebuffer[backbuf][0]);
GPU2D_Renderer->SetFramebuffer(Framebuffer[backbuf][1].get(), Framebuffer[backbuf][0].get());
}
}
void GPU::InitRenderer(int renderer) noexcept
void GPU::SetRenderer3D(std::unique_ptr<Renderer3D>&& renderer) noexcept
{
#ifdef OGLRENDERER_ENABLED
if (renderer == 1)
{
CurGLCompositor = GLCompositor::New(*this);
// Create opengl renderer
if (!CurGLCompositor)
{
// Fallback on software renderer
renderer = 0;
GPU3D.SetCurrentRenderer(std::make_unique<SoftRenderer>(*this));
}
GPU3D.SetCurrentRenderer(GLRenderer::New(*this));
if (!GPU3D.GetCurrentRenderer())
{
// Fallback on software renderer
CurGLCompositor.reset();
renderer = 0;
GPU3D.SetCurrentRenderer(std::make_unique<SoftRenderer>(*this));
}
}
else
#endif
{
if (renderer == nullptr)
GPU3D.SetCurrentRenderer(std::make_unique<SoftRenderer>(*this));
}
Renderer = renderer;
}
void GPU::DeInitRenderer() noexcept
{
// Delete the 3D renderer, if it exists
GPU3D.SetCurrentRenderer(nullptr);
#ifdef OGLRENDERER_ENABLED
// Delete the compositor, if one exists
CurGLCompositor.reset();
#endif
}
void GPU::ResetRenderer() noexcept
{
if (Renderer == 0)
{
GPU3D.GetCurrentRenderer()->Reset();
}
#ifdef OGLRENDERER_ENABLED
else
{
CurGLCompositor->Reset();
GPU3D.GetCurrentRenderer()->Reset();
}
#endif
}
void GPU::SetRenderSettings(int renderer, RenderSettings& settings) noexcept
{
if (renderer != Renderer)
{
DeInitRenderer();
InitRenderer(renderer);
}
GPU3D.SetCurrentRenderer(std::move(renderer));
int fbsize;
if (GPU3D.IsRendererAccelerated())
@ -379,34 +304,17 @@ void GPU::SetRenderSettings(int renderer, RenderSettings& settings) noexcept
else
fbsize = 256 * 192;
if (Framebuffer[0][0]) { delete[] Framebuffer[0][0]; Framebuffer[0][0] = nullptr; }
if (Framebuffer[1][0]) { delete[] Framebuffer[1][0]; Framebuffer[1][0] = nullptr; }
if (Framebuffer[0][1]) { delete[] Framebuffer[0][1]; Framebuffer[0][1] = nullptr; }
if (Framebuffer[1][1]) { delete[] Framebuffer[1][1]; Framebuffer[1][1] = nullptr; }
Framebuffer[0][0] = std::make_unique<u32[]>(fbsize);
Framebuffer[1][0] = std::make_unique<u32[]>(fbsize);
Framebuffer[0][1] = std::make_unique<u32[]>(fbsize);
Framebuffer[1][1] = std::make_unique<u32[]>(fbsize);
Framebuffer[0][0] = new u32[fbsize];
Framebuffer[1][0] = new u32[fbsize];
Framebuffer[0][1] = new u32[fbsize];
Framebuffer[1][1] = new u32[fbsize];
memset(Framebuffer[0][0], 0, fbsize*4);
memset(Framebuffer[1][0], 0, fbsize*4);
memset(Framebuffer[0][1], 0, fbsize*4);
memset(Framebuffer[1][1], 0, fbsize*4);
memset(Framebuffer[0][0].get(), 0, fbsize*4);
memset(Framebuffer[1][0].get(), 0, fbsize*4);
memset(Framebuffer[0][1].get(), 0, fbsize*4);
memset(Framebuffer[1][1].get(), 0, fbsize*4);
AssignFramebuffers();
if (Renderer == 0)
{
GPU3D.GetCurrentRenderer()->SetRenderSettings(settings);
}
#ifdef OGLRENDERER_ENABLED
else
{
CurGLCompositor->SetRenderSettings(settings);
GPU3D.GetCurrentRenderer()->SetRenderSettings(settings);
}
#endif
}
@ -1026,8 +934,8 @@ void GPU::BlankFrame() noexcept
else
fbsize = 256 * 192;
memset(Framebuffer[backbuf][0], 0, fbsize*4);
memset(Framebuffer[backbuf][1], 0, fbsize*4);
memset(Framebuffer[backbuf][0].get(), 0, fbsize*4);
memset(Framebuffer[backbuf][1].get(), 0, fbsize*4);
FrontBuffer = backbuf;
AssignFramebuffers();
@ -1123,11 +1031,9 @@ void GPU::StartScanline(u32 line) noexcept
GPU2D_B.VBlank();
GPU3D.VBlank();
#ifdef OGLRENDERER_ENABLED
// Need a better way to identify the openGL renderer in particular
if (GPU3D.IsRendererAccelerated())
CurGLCompositor->RenderFrame();
#endif
GPU3D.Blit();
}
}