aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Talavera-Greenberg <jesse@jesse.tg>2023-11-29 09:23:11 -0500
committerGitHub <noreply@github.com>2023-11-29 15:23:11 +0100
commit7caddf9615875e54b725bd7df266361c46d47b6f (patch)
tree966698578db1f764715ff4ee5e8ee4c787cbeb10
parente973236203292637eb7bd009a4cfbd6fd785181f (diff)
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`
-rw-r--r--src/GPU.cpp150
-rw-r--r--src/GPU.h36
-rw-r--r--src/GPU2D.h2
-rw-r--r--src/GPU2D_Soft.cpp71
-rw-r--r--src/GPU2D_Soft.h74
-rw-r--r--src/GPU3D.cpp17
-rw-r--r--src/GPU3D.h16
-rw-r--r--src/GPU3D_OpenGL.cpp43
-rw-r--r--src/GPU3D_OpenGL.h28
-rw-r--r--src/GPU3D_Soft.cpp14
-rw-r--r--src/GPU3D_Soft.h47
-rw-r--r--src/GPU_OpenGL.cpp110
-rw-r--r--src/GPU_OpenGL.h46
-rw-r--r--src/frontend/qt_sdl/main.cpp45
-rw-r--r--src/types.h3
15 files changed, 367 insertions, 335 deletions
diff --git a/src/GPU.cpp b/src/GPU.cpp
index 7a81f7d..c80e311 100644
--- a/src/GPU.cpp
+++ b/src/GPU.cpp
@@ -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] = new u32[fbsize];
- Framebuffer[1][0] = new u32[fbsize];
- Framebuffer[0][1] = new u32[fbsize];
- Framebuffer[1][1] = new u32[fbsize];
+ 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);
- 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();
}
}
diff --git a/src/GPU.h b/src/GPU.h
index 84210c9..21a05d5 100644
--- a/src/GPU.h
+++ b/src/GPU.h
@@ -25,10 +25,6 @@
#include "GPU3D.h"
#include "NonStupidBitfield.h"
-#ifdef OGLRENDERER_ENABLED
-#include "GPU_OpenGL.h"
-#endif
-
namespace melonDS
{
class GPU3D;
@@ -56,33 +52,30 @@ struct VRAMTrackingSet
NonStupidBitField<Size/VRAMDirtyGranularity> DeriveState(u32* currentMappings, GPU& gpu);
};
-struct RenderSettings
-{
- bool Soft_Threaded;
-
- int GL_ScaleFactor;
- bool GL_BetterPolygons;
-};
-
class GPU
{
public:
- GPU(melonDS::NDS& nds) noexcept;
+ explicit GPU(melonDS::NDS& nds, std::unique_ptr<Renderer3D>&& renderer3d = nullptr, std::unique_ptr<GPU2D::Renderer2D>&& renderer2d = nullptr) noexcept;
~GPU() noexcept;
void Reset() noexcept;
void Stop() noexcept;
void DoSavestate(Savestate* file) noexcept;
- [[deprecated("Set the renderer directly instead of using an integer code")]] void InitRenderer(int renderer) noexcept;
- void DeInitRenderer() noexcept;
- void ResetRenderer() noexcept;
-
- void SetRenderSettings(int renderer, RenderSettings& settings) noexcept;
+ /// Sets the active renderer to the renderer given in the provided pointer.
+ /// The pointer is moved-from, so it will be \c nullptr after this method is called.
+ /// If the pointer is \c nullptr, the renderer is reset to the default renderer.
+ void SetRenderer3D(std::unique_ptr<Renderer3D>&& renderer) noexcept;
+ [[nodiscard]] const Renderer3D& GetRenderer3D() const noexcept { return GPU3D.GetCurrentRenderer(); }
+ [[nodiscard]] Renderer3D& GetRenderer3D() noexcept { return GPU3D.GetCurrentRenderer(); }
u8* GetUniqueBankPtr(u32 mask, u32 offset) noexcept;
const u8* GetUniqueBankPtr(u32 mask, u32 offset) const noexcept;
+ void SetRenderer2D(std::unique_ptr<GPU2D::Renderer2D>&& renderer) noexcept { GPU2D_Renderer = std::move(renderer); }
+ [[nodiscard]] const GPU2D::Renderer2D& GetRenderer2D() const noexcept { return *GPU2D_Renderer; }
+ [[nodiscard]] GPU2D::Renderer2D& GetRenderer2D() noexcept { return *GPU2D_Renderer; }
+
void MapVRAM_AB(u32 bank, u8 cnt) noexcept;
void MapVRAM_CD(u32 bank, u8 cnt) noexcept;
void MapVRAM_E(u32 bank, u8 cnt) noexcept;
@@ -578,7 +571,7 @@ public:
u8* VRAMPtr_BOBJ[0x8] {};
int FrontBuffer = 0;
- u32* Framebuffer[2][2] {};
+ std::unique_ptr<u32[]> Framebuffer[2][2] {};
GPU2D::Unit GPU2D_A;
GPU2D::Unit GPU2D_B;
@@ -611,11 +604,6 @@ public:
u8 VRAMFlat_Texture[512*1024] {};
u8 VRAMFlat_TexPal[128*1024] {};
-
- int Renderer = 0;
-#ifdef OGLRENDERER_ENABLED
- std::unique_ptr<GLCompositor> CurGLCompositor = nullptr;
-#endif
private:
void ResetVRAMCache() noexcept;
void AssignFramebuffers() noexcept;
diff --git a/src/GPU2D.h b/src/GPU2D.h
index dd3bbf6..7367d07 100644
--- a/src/GPU2D.h
+++ b/src/GPU2D.h
@@ -35,7 +35,7 @@ public:
// take a reference to the GPU so we can access its state
// and ensure that it's not null
Unit(u32 num, melonDS::GPU& gpu);
-
+ virtual ~Unit() = default;
Unit(const Unit&) = delete;
Unit& operator=(const Unit&) = delete;
diff --git a/src/GPU2D_Soft.cpp b/src/GPU2D_Soft.cpp
index 9e7d849..6d0252c 100644
--- a/src/GPU2D_Soft.cpp
+++ b/src/GPU2D_Soft.cpp
@@ -27,68 +27,7 @@ namespace GPU2D
SoftRenderer::SoftRenderer(melonDS::GPU& gpu)
: Renderer2D(), GPU(gpu)
{
- // initialize mosaic table
- for (int m = 0; m < 16; m++)
- {
- for (int x = 0; x < 256; x++)
- {
- int offset = x % (m+1);
- MosaicTable[m][x] = offset;
- }
- }
-}
-
-u32 SoftRenderer::ColorBlend4(u32 val1, u32 val2, u32 eva, u32 evb)
-{
- u32 r = (((val1 & 0x00003F) * eva) + ((val2 & 0x00003F) * evb) + 0x000008) >> 4;
- u32 g = ((((val1 & 0x003F00) * eva) + ((val2 & 0x003F00) * evb) + 0x000800) >> 4) & 0x007F00;
- u32 b = ((((val1 & 0x3F0000) * eva) + ((val2 & 0x3F0000) * evb) + 0x080000) >> 4) & 0x7F0000;
-
- if (r > 0x00003F) r = 0x00003F;
- if (g > 0x003F00) g = 0x003F00;
- if (b > 0x3F0000) b = 0x3F0000;
-
- return r | g | b | 0xFF000000;
-}
-
-u32 SoftRenderer::ColorBlend5(u32 val1, u32 val2)
-{
- u32 eva = ((val1 >> 24) & 0x1F) + 1;
- u32 evb = 32 - eva;
-
- if (eva == 32) return val1;
-
- u32 r = (((val1 & 0x00003F) * eva) + ((val2 & 0x00003F) * evb) + 0x000010) >> 5;
- u32 g = ((((val1 & 0x003F00) * eva) + ((val2 & 0x003F00) * evb) + 0x001000) >> 5) & 0x007F00;
- u32 b = ((((val1 & 0x3F0000) * eva) + ((val2 & 0x3F0000) * evb) + 0x100000) >> 5) & 0x7F0000;
-
- if (r > 0x00003F) r = 0x00003F;
- if (g > 0x003F00) g = 0x003F00;
- if (b > 0x3F0000) b = 0x3F0000;
-
- return r | g | b | 0xFF000000;
-}
-
-u32 SoftRenderer::ColorBrightnessUp(u32 val, u32 factor, u32 bias)
-{
- u32 rb = val & 0x3F003F;
- u32 g = val & 0x003F00;
-
- rb += (((((0x3F003F - rb) * factor) + (bias*0x010001)) >> 4) & 0x3F003F);
- g += (((((0x003F00 - g ) * factor) + (bias*0x000100)) >> 4) & 0x003F00);
-
- return rb | g | 0xFF000000;
-}
-
-u32 SoftRenderer::ColorBrightnessDown(u32 val, u32 factor, u32 bias)
-{
- u32 rb = val & 0x3F003F;
- u32 g = val & 0x003F00;
-
- rb -= ((((rb * factor) + (bias*0x010001)) >> 4) & 0x3F003F);
- g -= ((((g * factor) + (bias*0x000100)) >> 4) & 0x003F00);
-
- return rb | g | 0xFF000000;
+ // mosaic table is initialized at compile-time
}
u32 SoftRenderer::ColorComposite(int i, u32 val1, u32 val2)
@@ -365,11 +304,11 @@ void SoftRenderer::DrawScanline(u32 line, Unit* unit)
void SoftRenderer::VBlankEnd(Unit* unitA, Unit* unitB)
{
#ifdef OGLRENDERER_ENABLED
- if (GPU.GPU3D.IsRendererAccelerated())
+ if (Renderer3D& renderer3d = GPU.GPU3D.GetCurrentRenderer(); renderer3d.Accelerated)
{
if ((unitA->CaptureCnt & (1<<31)) && (((unitA->CaptureCnt >> 29) & 0x3) != 1))
{
- reinterpret_cast<GLRenderer*>(GPU.GPU3D.GetCurrentRenderer())->PrepareCaptureFrame();
+ renderer3d.PrepareCaptureFrame();
}
}
#endif
@@ -779,7 +718,7 @@ void SoftRenderer::DrawScanline_BGOBJ(u32 line)
memset(WindowMask, 0xFF, 256);
ApplySpriteMosaicX();
- CurBGXMosaicTable = MosaicTable[CurUnit->BGMosaicSize[0]];
+ CurBGXMosaicTable = MosaicTable[CurUnit->BGMosaicSize[0]].data();
switch (CurUnit->DispCnt & 0x7)
{
@@ -1564,7 +1503,7 @@ void SoftRenderer::ApplySpriteMosaicX()
u32* objLine = OBJLine[CurUnit->Num];
- u8* curOBJXMosaicTable = MosaicTable[CurUnit->OBJMosaicSize[1]];
+ u8* curOBJXMosaicTable = MosaicTable[CurUnit->OBJMosaicSize[1]].data();
u32 lastcolor = objLine[0];
diff --git a/src/GPU2D_Soft.h b/src/GPU2D_Soft.h
index 86943d3..ca242a5 100644
--- a/src/GPU2D_Soft.h
+++ b/src/GPU2D_Soft.h
@@ -49,12 +49,74 @@ private:
u32 NumSprites[2];
u8* CurBGXMosaicTable;
- u8 MosaicTable[16][256];
-
- u32 ColorBlend4(u32 val1, u32 val2, u32 eva, u32 evb);
- u32 ColorBlend5(u32 val1, u32 val2);
- u32 ColorBrightnessUp(u32 val, u32 factor, u32 bias);
- u32 ColorBrightnessDown(u32 val, u32 factor, u32 bias);
+ array2d<u8, 16, 256> MosaicTable = []() constexpr
+ {
+ array2d<u8, 16, 256> table {};
+ // initialize mosaic table
+ for (int m = 0; m < 16; m++)
+ {
+ for (int x = 0; x < 256; x++)
+ {
+ int offset = x % (m+1);
+ table[m][x] = offset;
+ }
+ }
+
+ return table;
+ }();
+
+ static constexpr u32 ColorBlend4(u32 val1, u32 val2, u32 eva, u32 evb) noexcept
+ {
+ u32 r = (((val1 & 0x00003F) * eva) + ((val2 & 0x00003F) * evb) + 0x000008) >> 4;
+ u32 g = ((((val1 & 0x003F00) * eva) + ((val2 & 0x003F00) * evb) + 0x000800) >> 4) & 0x007F00;
+ u32 b = ((((val1 & 0x3F0000) * eva) + ((val2 & 0x3F0000) * evb) + 0x080000) >> 4) & 0x7F0000;
+
+ if (r > 0x00003F) r = 0x00003F;
+ if (g > 0x003F00) g = 0x003F00;
+ if (b > 0x3F0000) b = 0x3F0000;
+
+ return r | g | b | 0xFF000000;
+ }
+
+ static constexpr u32 ColorBlend5(u32 val1, u32 val2) noexcept
+ {
+ u32 eva = ((val1 >> 24) & 0x1F) + 1;
+ u32 evb = 32 - eva;
+
+ if (eva == 32) return val1;
+
+ u32 r = (((val1 & 0x00003F) * eva) + ((val2 & 0x00003F) * evb) + 0x000010) >> 5;
+ u32 g = ((((val1 & 0x003F00) * eva) + ((val2 & 0x003F00) * evb) + 0x001000) >> 5) & 0x007F00;
+ u32 b = ((((val1 & 0x3F0000) * eva) + ((val2 & 0x3F0000) * evb) + 0x100000) >> 5) & 0x7F0000;
+
+ if (r > 0x00003F) r = 0x00003F;
+ if (g > 0x003F00) g = 0x003F00;
+ if (b > 0x3F0000) b = 0x3F0000;
+
+ return r | g | b | 0xFF000000;
+ }
+
+ static constexpr u32 ColorBrightnessUp(u32 val, u32 factor, u32 bias) noexcept
+ {
+ u32 rb = val & 0x3F003F;
+ u32 g = val & 0x003F00;
+
+ rb += (((((0x3F003F - rb) * factor) + (bias*0x010001)) >> 4) & 0x3F003F);
+ g += (((((0x003F00 - g ) * factor) + (bias*0x000100)) >> 4) & 0x003F00);
+
+ return rb | g | 0xFF000000;
+ }
+
+ static constexpr u32 ColorBrightnessDown(u32 val, u32 factor, u32 bias) noexcept
+ {
+ u32 rb = val & 0x3F003F;
+ u32 g = val & 0x003F00;
+
+ rb -= ((((rb * factor) + (bias*0x010001)) >> 4) & 0x3F003F);
+ g -= ((((g * factor) + (bias*0x000100)) >> 4) & 0x003F00);
+
+ return rb | g | 0xFF000000;
+ }
u32 ColorComposite(int i, u32 val1, u32 val2);
template<u32 bgmode> void DrawScanlineBGMode(u32 line);
diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp
index 5603a13..049ae58 100644
--- a/src/GPU3D.cpp
+++ b/src/GPU3D.cpp
@@ -22,6 +22,7 @@
#include "NDS.h"
#include "GPU.h"
#include "FIFO.h"
+#include "GPU3D_Soft.h"
#include "Platform.h"
namespace melonDS
@@ -139,7 +140,9 @@ const u8 CmdNumParams[256] =
void MatrixLoadIdentity(s32* m);
-GPU3D::GPU3D(melonDS::NDS& nds) noexcept : NDS(nds)
+GPU3D::GPU3D(melonDS::NDS& nds, std::unique_ptr<Renderer3D>&& renderer) noexcept :
+ NDS(nds),
+ CurrentRenderer(renderer ? std::move(renderer) : std::make_unique<SoftRenderer>(nds.GPU))
{
}
@@ -2336,6 +2339,12 @@ void GPU3D::RestartFrame() noexcept
CurrentRenderer->RestartFrame();
}
+void GPU3D::Stop() noexcept
+{
+ if (CurrentRenderer)
+ CurrentRenderer->Stop();
+}
+
bool YSort(Polygon* a, Polygon* b)
{
@@ -2888,6 +2897,12 @@ void GPU3D::Write32(u32 addr, u32 val) noexcept
Log(LogLevel::Debug, "unknown GPU3D write32 %08X %08X\n", addr, val);
}
+void GPU3D::Blit() noexcept
+{
+ if (CurrentRenderer)
+ CurrentRenderer->Blit();
+}
+
Renderer3D::Renderer3D(bool Accelerated)
: Accelerated(Accelerated)
{ }
diff --git a/src/GPU3D.h b/src/GPU3D.h
index 1d3e126..8e743fa 100644
--- a/src/GPU3D.h
+++ b/src/GPU3D.h
@@ -27,7 +27,7 @@
namespace melonDS
{
-struct RenderSettings;
+class GPU;
struct Vertex
{
@@ -86,7 +86,7 @@ class NDS;
class GPU3D
{
public:
- GPU3D(melonDS::NDS& nds) noexcept;
+ GPU3D(melonDS::NDS& nds, std::unique_ptr<Renderer3D>&& renderer = nullptr) noexcept;
~GPU3D() noexcept = default;
void Reset() noexcept;
@@ -106,6 +106,7 @@ public:
void VCount215() noexcept;
void RestartFrame() noexcept;
+ void Stop() noexcept;
void SetRenderXPos(u16 xpos) noexcept;
[[nodiscard]] u16 GetRenderXPos() const noexcept { return RenderXPos; }
@@ -114,8 +115,8 @@ public:
void WriteToGXFIFO(u32 val) noexcept;
[[nodiscard]] bool IsRendererAccelerated() const noexcept;
- [[nodiscard]] Renderer3D* GetCurrentRenderer() noexcept { return CurrentRenderer.get(); }
- [[nodiscard]] const Renderer3D* GetCurrentRenderer() const noexcept { return CurrentRenderer.get(); }
+ [[nodiscard]] Renderer3D& GetCurrentRenderer() noexcept { return *CurrentRenderer; }
+ [[nodiscard]] const Renderer3D& GetCurrentRenderer() const noexcept { return *CurrentRenderer; }
void SetCurrentRenderer(std::unique_ptr<Renderer3D>&& renderer) noexcept { CurrentRenderer = std::move(renderer); }
u8 Read8(u32 addr) noexcept;
@@ -124,6 +125,7 @@ public:
void Write8(u32 addr, u8 val) noexcept;
void Write16(u32 addr, u16 val) noexcept;
void Write32(u32 addr, u32 val) noexcept;
+ void Blit() noexcept;
private:
melonDS::NDS& NDS;
typedef union
@@ -338,13 +340,13 @@ public:
// are more detailed "traits" that we can ask of the Renderer3D type
const bool Accelerated;
- virtual void SetRenderSettings(const RenderSettings& settings) noexcept = 0;
-
virtual void VCount144() {};
-
+ virtual void Stop() {}
virtual void RenderFrame() = 0;
virtual void RestartFrame() {};
virtual u32* GetLine(int line) = 0;
+ virtual void Blit() {};
+ virtual void PrepareCaptureFrame() {}
protected:
Renderer3D(bool Accelerated);
};
diff --git a/src/GPU3D_OpenGL.cpp b/src/GPU3D_OpenGL.cpp
index fb9f246..bee0430 100644
--- a/src/GPU3D_OpenGL.cpp
+++ b/src/GPU3D_OpenGL.cpp
@@ -97,7 +97,10 @@ void SetupDefaultTexParams(GLuint tex)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
-GLRenderer::GLRenderer(melonDS::GPU& gpu) noexcept : Renderer3D(true), GPU(gpu)
+GLRenderer::GLRenderer(GLCompositor&& compositor, melonDS::GPU& gpu) noexcept :
+ Renderer3D(true),
+ GPU(gpu),
+ CurGLCompositor(std::move(compositor))
{
// GLRenderer::New() will be used to actually initialize the renderer;
// The various glDelete* functions silently ignore invalid IDs,
@@ -108,9 +111,14 @@ std::unique_ptr<GLRenderer> GLRenderer::New(melonDS::GPU& gpu) noexcept
{
assert(glEnable != nullptr);
+ std::optional<GLCompositor> compositor = GLCompositor::New();
+ if (!compositor)
+ return nullptr;
+
// Will be returned if the initialization succeeds,
// or cleaned up via RAII if it fails.
- std::unique_ptr<GLRenderer> result = std::unique_ptr<GLRenderer>(new GLRenderer(gpu));
+ std::unique_ptr<GLRenderer> result = std::unique_ptr<GLRenderer>(new GLRenderer(std::move(*compositor), gpu));
+ compositor = std::nullopt;
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
@@ -327,14 +335,29 @@ GLRenderer::~GLRenderer()
void GLRenderer::Reset()
{
+ // This is where the compositor's Reset() method would be called,
+ // except there's no such method right now.
+}
+
+void GLRenderer::SetBetterPolygons(bool betterpolygons) noexcept
+{
+ SetRenderSettings(betterpolygons, ScaleFactor);
}
-void GLRenderer::SetRenderSettings(const RenderSettings& settings) noexcept
+void GLRenderer::SetScaleFactor(int scale) noexcept
{
- int scale = settings.GL_ScaleFactor;
+ SetRenderSettings(BetterPolygons, scale);
+}
+
+void GLRenderer::SetRenderSettings(bool betterpolygons, int scale) noexcept
+{
+ if (betterpolygons == BetterPolygons && scale == ScaleFactor)
+ return;
+
+ CurGLCompositor.SetScaleFactor(scale);
ScaleFactor = scale;
- BetterPolygons = settings.GL_BetterPolygons;
+ BetterPolygons = betterpolygons;
ScreenW = 256 * scale;
ScreenH = 192 * scale;
@@ -1302,6 +1325,11 @@ void GLRenderer::RenderFrame()
FrontBuffer = FrontBuffer ? 0 : 1;
}
+void GLRenderer::Stop()
+{
+ CurGLCompositor.Stop(GPU);
+}
+
void GLRenderer::PrepareCaptureFrame()
{
// TODO: make sure this picks the right buffer when doing antialiasing
@@ -1317,6 +1345,11 @@ void GLRenderer::PrepareCaptureFrame()
glReadPixels(0, 0, 256, 192, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
}
+void GLRenderer::Blit()
+{
+ CurGLCompositor.RenderFrame(GPU, *this);
+}
+
u32* GLRenderer::GetLine(int line)
{
int stride = 256;
diff --git a/src/GPU3D_OpenGL.h b/src/GPU3D_OpenGL.h
index 0bc20d8..63ee8de 100644
--- a/src/GPU3D_OpenGL.h
+++ b/src/GPU3D_OpenGL.h
@@ -20,7 +20,7 @@
#ifdef OGLRENDERER_ENABLED
#include "GPU3D.h"
-
+#include "GPU_OpenGL.h"
#include "OpenGLSupport.h"
namespace melonDS
@@ -30,22 +30,31 @@ class GPU;
class GLRenderer : public Renderer3D
{
public:
- virtual ~GLRenderer() override;
- virtual void Reset() override;
+ ~GLRenderer() override;
+ void Reset() override;
- virtual void SetRenderSettings(const RenderSettings& settings) noexcept override;
+ void SetRenderSettings(bool betterpolygons, int scale) noexcept;
+ void SetBetterPolygons(bool betterpolygons) noexcept;
+ void SetScaleFactor(int scale) noexcept;
+ [[nodiscard]] bool GetBetterPolygons() const noexcept { return BetterPolygons; }
+ [[nodiscard]] int GetScaleFactor() const noexcept { return ScaleFactor; }
- virtual void VCount144() override {};
- virtual void RenderFrame() override;
- virtual u32* GetLine(int line) override;
+ void VCount144() override {};
+ void RenderFrame() override;
+ void Stop() override;
+ u32* GetLine(int line) override;
void SetupAccelFrame();
- void PrepareCaptureFrame();
+ void PrepareCaptureFrame() override;
+ void Blit() override;
+
+ [[nodiscard]] const GLCompositor& GetCompositor() const noexcept { return CurGLCompositor; }
+ GLCompositor& GetCompositor() noexcept { return CurGLCompositor; }
static std::unique_ptr<GLRenderer> New(melonDS::GPU& gpu) noexcept;
private:
// Used by New()
- GLRenderer(melonDS::GPU& gpu) noexcept;
+ GLRenderer(GLCompositor&& compositor, GPU& gpu) noexcept;
// GL version requirements
// * texelFetch: 3.0 (GLSL 1.30) (3.2/1.50 for MS)
@@ -66,6 +75,7 @@ private:
};
melonDS::GPU& GPU;
+ GLCompositor CurGLCompositor;
RendererPolygon PolygonList[2048] {};
bool BuildRenderShader(u32 flags, const char* vs, const char* fs);
diff --git a/src/GPU3D_Soft.cpp b/src/GPU3D_Soft.cpp
index 809bd59..03c6265 100644
--- a/src/GPU3D_Soft.cpp
+++ b/src/GPU3D_Soft.cpp
@@ -71,14 +71,13 @@ void SoftRenderer::SetupRenderThread()
}
-SoftRenderer::SoftRenderer(melonDS::GPU& gpu) noexcept
- : Renderer3D(false), GPU(gpu)
+SoftRenderer::SoftRenderer(melonDS::GPU& gpu, bool threaded) noexcept
+ : Renderer3D(false), GPU(gpu), Threaded(threaded)
{
Sema_RenderStart = Platform::Semaphore_Create();
Sema_RenderDone = Platform::Semaphore_Create();
Sema_ScanlineCount = Platform::Semaphore_Create();
- Threaded = false;
RenderThreadRunning = false;
RenderThreadRendering = false;
RenderThread = nullptr;
@@ -104,10 +103,13 @@ void SoftRenderer::Reset()
SetupRenderThread();
}
-void SoftRenderer::SetRenderSettings(const RenderSettings& settings) noexcept
+void SoftRenderer::SetThreaded(bool threaded) noexcept
{
- Threaded = settings.Soft_Threaded;
- SetupRenderThread();
+ if (Threaded != threaded)
+ {
+ Threaded = threaded;
+ SetupRenderThread();
+ }
}
void SoftRenderer::TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha)
diff --git a/src/GPU3D_Soft.h b/src/GPU3D_Soft.h
index 9fb9a71..2f5664e 100644
--- a/src/GPU3D_Soft.h
+++ b/src/GPU3D_Soft.h
@@ -29,16 +29,17 @@ namespace melonDS
class SoftRenderer : public Renderer3D
{
public:
- SoftRenderer(melonDS::GPU& gpu) noexcept;
- virtual ~SoftRenderer() override;
- virtual void Reset() override;
+ SoftRenderer(melonDS::GPU& gpu, bool threaded = false) noexcept;
+ ~SoftRenderer() override;
+ void Reset() override;
- virtual void SetRenderSettings(const RenderSettings& settings) noexcept override;
+ void SetThreaded(bool threaded) noexcept;
+ [[nodiscard]] bool IsThreaded() const noexcept { return Threaded; }
- virtual void VCount144() override;
- virtual void RenderFrame() override;
- virtual void RestartFrame() override;
- virtual u32* GetLine(int line) override;
+ void VCount144() override;
+ void RenderFrame() override;
+ void RestartFrame() override;
+ u32* GetLine(int line) override;
void SetupRenderThread();
void StopRenderThread();
@@ -65,13 +66,13 @@ private:
class Interpolator
{
public:
- Interpolator() {}
- Interpolator(s32 x0, s32 x1, s32 w0, s32 w1)
+ constexpr Interpolator() {}
+ constexpr Interpolator(s32 x0, s32 x1, s32 w0, s32 w1)
{
Setup(x0, x1, w0, w1);
}
- void Setup(s32 x0, s32 x1, s32 w0, s32 w1)
+ constexpr void Setup(s32 x0, s32 x1, s32 w0, s32 w1)
{
this->x0 = x0;
this->x1 = x1;
@@ -123,7 +124,7 @@ private:
}
}
- void SetX(s32 x)
+ constexpr void SetX(s32 x)
{
x -= x0;
this->x = x;
@@ -139,7 +140,7 @@ private:
}
}
- s32 Interpolate(s32 y0, s32 y1)
+ constexpr s32 Interpolate(s32 y0, s32 y1) const
{
if (xdiff == 0 || y0 == y1) return y0;
@@ -161,7 +162,7 @@ private:
}
}
- s32 InterpolateZ(s32 z0, s32 z1, bool wbuffer)
+ constexpr s32 InterpolateZ(s32 z0, s32 z1, bool wbuffer) const
{
if (xdiff == 0 || z0 == z1) return z0;
@@ -228,9 +229,9 @@ private:
class Slope
{
public:
- Slope() {}
+ constexpr Slope() {}
- s32 SetupDummy(s32 x0)
+ constexpr s32 SetupDummy(s32 x0)
{
dx = 0;
@@ -249,7 +250,7 @@ private:
return x0;
}
- s32 Setup(s32 x0, s32 x1, s32 y0, s32 y1, s32 w0, s32 w1, s32 y)
+ constexpr s32 Setup(s32 x0, s32 x1, s32 y0, s32 y1, s32 w0, s32 w1, s32 y)
{
this->x0 = x0;
this->y = y;
@@ -293,7 +294,7 @@ private:
XMajor = (Increment > 0x40000);
- if (side)
+ if constexpr (side)
{
// right
@@ -324,7 +325,7 @@ private:
return x;
}
- s32 Step()
+ constexpr s32 Step()
{
dx += Increment;
y++;
@@ -334,7 +335,7 @@ private:
return x;
}
- s32 XVal()
+ constexpr s32 XVal() const
{
s32 ret;
if (Negative) ret = x0 - (dx >> 18);
@@ -346,7 +347,7 @@ private:
}
template<bool swapped>
- void EdgeParams_XMajor(s32* length, s32* coverage)
+ constexpr void EdgeParams_XMajor(s32* length, s32* coverage) const
{
// only do length calc for right side when swapped as it's
// only needed for aa calcs, as actual line spans are broken
@@ -372,7 +373,7 @@ private:
}
template<bool swapped>
- void EdgeParams_YMajor(s32* length, s32* coverage)
+ constexpr void EdgeParams_YMajor(s32* length, s32* coverage) const
{
*length = 1;
@@ -404,7 +405,7 @@ private:
}
template<bool swapped>
- void EdgeParams(s32* length, s32* coverage)
+ constexpr void EdgeParams(s32* length, s32* coverage) const
{
if (XMajor)
return EdgeParams_XMajor<swapped>(length, coverage);
diff --git a/src/GPU_OpenGL.cpp b/src/GPU_OpenGL.cpp
index 2db3810..2e2857c 100644
--- a/src/GPU_OpenGL.cpp
+++ b/src/GPU_OpenGL.cpp
@@ -33,13 +33,13 @@ namespace melonDS
using namespace OpenGL;
-std::unique_ptr<GLCompositor> GLCompositor::New(melonDS::GPU& gpu) noexcept
+std::optional<GLCompositor> GLCompositor::New() noexcept
{
assert(glBindAttribLocation != nullptr);
std::array<GLuint, 3> CompShader {};
if (!OpenGL::BuildShaderProgram(kCompositorVS, kCompositorFS_Nearest, &CompShader[0], "CompositorShader"))
- return nullptr;
+ return std::nullopt;
glBindAttribLocation(CompShader[2], 0, "vPosition");
glBindAttribLocation(CompShader[2], 1, "vTexcoord");
@@ -48,12 +48,12 @@ std::unique_ptr<GLCompositor> GLCompositor::New(melonDS::GPU& gpu) noexcept
if (!OpenGL::LinkShaderProgram(CompShader.data()))
// OpenGL::LinkShaderProgram already deletes the shader program object
// if linking the shaders together failed.
- return nullptr;
+ return std::nullopt;
- return std::unique_ptr<GLCompositor>(new GLCompositor(CompShader, gpu));
+ return { GLCompositor(CompShader) };
}
-GLCompositor::GLCompositor(std::array<GLuint, 3> compShader, melonDS::GPU& gpu) noexcept : CompShader(compShader), GPU(gpu)
+GLCompositor::GLCompositor(std::array<GLuint, 3> compShader) noexcept : CompShader(compShader)
{
CompScaleLoc = glGetUniformLocation(CompShader[2], "u3DScale");
Comp3DXPosLoc = glGetUniformLocation(CompShader[2], "u3DXPos");
@@ -92,7 +92,7 @@ GLCompositor::GLCompositor(std::array<GLuint, 3> compShader, melonDS::GPU& gpu)
glGenBuffers(1, &CompVertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, CompVertexBufferID);
- glBufferData(GL_ARRAY_BUFFER, sizeof(CompVertices), CompVertices, GL_STATIC_DRAW);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(CompVertices), &CompVertices[0], GL_STATIC_DRAW);
glGenVertexArrays(1, &CompVertexArrayID);
glBindVertexArray(CompVertexArrayID);
@@ -101,7 +101,7 @@ GLCompositor::GLCompositor(std::array<GLuint, 3> compShader, melonDS::GPU& gpu)
glEnableVertexAttribArray(1); // texcoord
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(CompVertex), (void*)(offsetof(CompVertex, Texcoord)));
- glGenFramebuffers(2, CompScreenOutputFB);
+ glGenFramebuffers(CompScreenOutputFB.size(), &CompScreenOutputFB[0]);
glGenTextures(1, &CompScreenInputTex);
glActiveTexture(GL_TEXTURE0);
@@ -112,10 +112,10 @@ GLCompositor::GLCompositor(std::array<GLuint, 3> compShader, melonDS::GPU& gpu)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI, 256*3 + 1, 192*2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, NULL);
- glGenTextures(2, CompScreenOutputTex);
- for (int i = 0; i < 2; i++)
+ glGenTextures(CompScreenOutputTex.size(), &CompScreenOutputTex[0]);
+ for (GLuint i : CompScreenOutputTex)
{
- glBindTexture(GL_TEXTURE_2D, CompScreenOutputTex[i]);
+ glBindTexture(GL_TEXTURE_2D, i);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -129,9 +129,9 @@ GLCompositor::~GLCompositor()
{
assert(glDeleteFramebuffers != nullptr);
- glDeleteFramebuffers(2, CompScreenOutputFB);
+ glDeleteFramebuffers(CompScreenOutputFB.size(), &CompScreenOutputFB[0]);
glDeleteTextures(1, &CompScreenInputTex);
- glDeleteTextures(2, CompScreenOutputTex);
+ glDeleteTextures(CompScreenOutputTex.size(), &CompScreenOutputTex[0]);
glDeleteVertexArrays(1, &CompVertexArrayID);
glDeleteBuffers(1, &CompVertexBufferID);
@@ -139,14 +139,75 @@ GLCompositor::~GLCompositor()
OpenGL::DeleteShaderProgram(CompShader.data());
}
-void GLCompositor::Reset()
+
+GLCompositor::GLCompositor(GLCompositor&& other) noexcept :
+ Scale(other.Scale),
+ ScreenH(other.ScreenH),
+ ScreenW(other.ScreenW),
+ CompScaleLoc(other.CompScaleLoc),
+ Comp3DXPosLoc(other.Comp3DXPosLoc),
+ CompVertices(other.CompVertices),
+ CompShader(other.CompShader),
+ CompVertexBufferID(other.CompVertexBufferID),
+ CompVertexArrayID(other.CompVertexArrayID),
+ CompScreenInputTex(other.CompScreenInputTex),
+ CompScreenOutputTex(other.CompScreenOutputTex),
+ CompScreenOutputFB(other.CompScreenOutputFB)
{
+ other.CompScreenOutputFB = {};
+ other.CompScreenInputTex = {};
+ other.CompScreenOutputTex = {};
+ other.CompVertexArrayID = {};
+ other.CompVertexBufferID = {};
+ other.CompShader = {};
+}
+
+GLCompositor& GLCompositor::operator=(GLCompositor&& other) noexcept
+{
+ if (this != &other)
+ {
+ Scale = other.Scale;
+ ScreenH = other.ScreenH;
+ ScreenW = other.ScreenW;
+ CompScaleLoc = other.CompScaleLoc;
+ Comp3DXPosLoc = other.Comp3DXPosLoc;
+ CompVertices = other.CompVertices;
+
+ // Clean up these resources before overwriting them
+ OpenGL::DeleteShaderProgram(CompShader.data());
+ CompShader = other.CompShader;
+
+ glDeleteBuffers(1, &CompVertexBufferID);
+ CompVertexBufferID = other.CompVertexBufferID;
+
+ glDeleteVertexArrays(1, &CompVertexArrayID);
+ CompVertexArrayID = other.CompVertexArrayID;
+
+ glDeleteTextures(1, &CompScreenInputTex);
+ CompScreenInputTex = other.CompScreenInputTex;
+
+ glDeleteTextures(CompScreenOutputTex.size(), &CompScreenOutputTex[0]);
+ CompScreenOutputTex = other.CompScreenOutputTex;
+
+ glDeleteFramebuffers(CompScreenOutputFB.size(), &CompScreenOutputFB[0]);
+ CompScreenOutputFB = other.CompScreenOutputFB;
+
+ other.CompScreenOutputFB = {};
+ other.CompScreenInputTex = {};
+ other.CompScreenOutputTex = {};
+ other.CompVertexArrayID = {};
+ other.CompVertexBufferID = {};
+ other.CompShader = {};
+ }
+
+ return *this;
}
-void GLCompositor::SetRenderSettings(const RenderSettings& settings) noexcept
+void GLCompositor::SetScaleFactor(int scale) noexcept
{
- int scale = settings.GL_ScaleFactor;
+ if (scale == Scale)
+ return;
Scale = scale;
ScreenW = 256 * scale;
@@ -170,13 +231,12 @@ void GLCompositor::SetRenderSettings(const RenderSettings& settings) noexcept
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
-void GLCompositor::Stop()
+void GLCompositor::Stop(const GPU& gpu) noexcept
{
for (int i = 0; i < 2; i++)
{
- int frontbuf = GPU.FrontBuffer;
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, CompScreenOutputFB[frontbuf]);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, CompScreenOutputFB[gpu.FrontBuffer]);
glClear(GL_COLOR_BUFFER_BIT);
}
@@ -184,9 +244,9 @@ void GLCompositor::Stop()
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
-void GLCompositor::RenderFrame()
+void GLCompositor::RenderFrame(const GPU& gpu, GLRenderer& renderer) noexcept
{
- int frontbuf = GPU.FrontBuffer;
+ int frontbuf = gpu.FrontBuffer;
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, CompScreenOutputFB[frontbuf]);
@@ -204,21 +264,21 @@ void GLCompositor::RenderFrame()
glUniform1ui(CompScaleLoc, Scale);
// TODO: support setting this midframe, if ever needed
- glUniform1i(Comp3DXPosLoc, ((int)GPU.GPU3D.GetRenderXPos() << 23) >> 23);
+ glUniform1i(Comp3DXPosLoc, ((int)gpu.GPU3D.GetRenderXPos() << 23) >> 23);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, CompScreenInputTex);
- if (GPU.Framebuffer[frontbuf][0] && GPU.Framebuffer[frontbuf][1])
+ if (gpu.Framebuffer[frontbuf][0] && gpu.Framebuffer[frontbuf][1])
{
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256*3 + 1, 192, GL_RGBA_INTEGER,
- GL_UNSIGNED_BYTE, GPU.Framebuffer[frontbuf][0]);
+ GL_UNSIGNED_BYTE, gpu.Framebuffer[frontbuf][0].get());
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192, 256*3 + 1, 192, GL_RGBA_INTEGER,
- GL_UNSIGNED_BYTE, GPU.Framebuffer[frontbuf][1]);
+ GL_UNSIGNED_BYTE, gpu.Framebuffer[frontbuf][1].get());
}
glActiveTexture(GL_TEXTURE1);
- reinterpret_cast<GLRenderer*>(GPU.GPU3D.GetCurrentRenderer())->SetupAccelFrame();
+ renderer.SetupAccelFrame();
glBindBuffer(GL_ARRAY_BUFFER, CompVertexBufferID);
glBindVertexArray(CompVertexArrayID);
diff --git a/src/GPU_OpenGL.h b/src/GPU_OpenGL.h
index 68462a9..9c04096 100644
--- a/src/GPU_OpenGL.h
+++ b/src/GPU_OpenGL.h
@@ -21,51 +21,51 @@
#include "OpenGLSupport.h"
#include <array>
-#include <memory>
+#include <optional>
namespace melonDS
{
class GPU;
struct RenderSettings;
-
+class GLRenderer;
class GLCompositor
{
public:
- static std::unique_ptr<GLCompositor> New(melonDS::GPU& gpu) noexcept;
+ static std::optional<GLCompositor> New() noexcept;
GLCompositor(const GLCompositor&) = delete;
GLCompositor& operator=(const GLCompositor&) = delete;
+ GLCompositor(GLCompositor&&) noexcept;
+ GLCompositor& operator=(GLCompositor&&) noexcept;
~GLCompositor();
- void Reset();
-
- void SetRenderSettings(const RenderSettings& settings) noexcept;
+ void SetScaleFactor(int scale) noexcept;
+ [[nodiscard]] int GetScaleFactor() const noexcept { return Scale; }
- void Stop();
- void RenderFrame();
+ void Stop(const GPU& gpu) noexcept;
+ void RenderFrame(const GPU& gpu, GLRenderer& renderer) noexcept;
void BindOutputTexture(int buf);
private:
- GLCompositor(std::array<GLuint, 3> CompShader, melonDS::GPU& gpu) noexcept;
- melonDS::GPU& GPU;
- int Scale;
- int ScreenH, ScreenW;
+ GLCompositor(std::array<GLuint, 3> CompShader) noexcept;
+ int Scale = 0;
+ int ScreenH = 0, ScreenW = 0;
- std::array<GLuint, 3> CompShader;
- GLuint CompScaleLoc;
- GLuint Comp3DXPosLoc;
+ std::array<GLuint, 3> CompShader {};
+ GLuint CompScaleLoc = 0;
+ GLuint Comp3DXPosLoc = 0;
- GLuint CompVertexBufferID;
- GLuint CompVertexArrayID;
+ GLuint CompVertexBufferID = 0;
+ GLuint CompVertexArrayID = 0;
struct CompVertex
{
- float Position[2];
- float Texcoord[2];
+ std::array<float, 2> Position {};
+ std::array<float, 2> Texcoord {};
};
- CompVertex CompVertices[2 * 3*2];
+ std::array<CompVertex, 2*3*2> CompVertices {};
- GLuint CompScreenInputTex;
- GLuint CompScreenOutputTex[2];
- GLuint CompScreenOutputFB[2];
+ GLuint CompScreenInputTex = 0;
+ std::array<GLuint, 2> CompScreenOutputTex {};
+ std::array<GLuint, 2> CompScreenOutputFB {};
};
}
diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp
index 54a6f14..a0ac086 100644
--- a/src/frontend/qt_sdl/main.cpp
+++ b/src/frontend/qt_sdl/main.cpp
@@ -93,6 +93,8 @@
#include "RTC.h"
#include "DSi.h"
#include "DSi_I2C.h"
+#include "GPU3D_Soft.h"
+#include "GPU3D_OpenGL.h"
#include "Savestate.h"
@@ -163,7 +165,6 @@ EmuThread* emuThread;
int autoScreenSizing = 0;
int videoRenderer;
-RenderSettings videoSettings;
bool videoSettingsDirty;
CameraManager* camManager[2];
@@ -350,9 +351,6 @@ void EmuThread::run()
autoScreenSizing = 0;
videoSettingsDirty = false;
- videoSettings.Soft_Threaded = Config::Threaded3D != 0;
- videoSettings.GL_ScaleFactor = Config::GL_ScaleFactor;
- videoSettings.GL_BetterPolygons = Config::GL_BetterPolygons;
if (mainWindow->hasOGL)
{
@@ -364,8 +362,16 @@ void EmuThread::run()
videoRenderer = 0;
}
- NDS->GPU.InitRenderer(videoRenderer);
- NDS->GPU.SetRenderSettings(videoRenderer, videoSettings);
+ if (videoRenderer == 0)
+ { // If we're using the software renderer...
+ NDS->GPU.SetRenderer3D(std::make_unique<SoftRenderer>(NDS->GPU, Config::Threaded3D != 0));
+ }
+ else
+ {
+ auto glrenderer = melonDS::GLRenderer::New(NDS->GPU);
+ glrenderer->SetRenderSettings(Config::GL_BetterPolygons, Config::GL_ScaleFactor);
+ NDS->GPU.SetRenderer3D(std::move(glrenderer));
+ }
NDS->SPU.SetInterpolation(Config::AudioInterp);
@@ -491,11 +497,16 @@ void EmuThread::run()
videoSettingsDirty = false;
- videoSettings.Soft_Threaded = Config::Threaded3D != 0;
- videoSettings.GL_ScaleFactor = Config::GL_ScaleFactor;
- videoSettings.GL_BetterPolygons = Config::GL_BetterPolygons;
-
- NDS->GPU.SetRenderSettings(videoRenderer, videoSettings);
+ if (videoRenderer == 0)
+ { // If we're using the software renderer...
+ NDS->GPU.SetRenderer3D(std::make_unique<SoftRenderer>(NDS->GPU, Config::Threaded3D != 0));
+ }
+ else
+ {
+ auto glrenderer = melonDS::GLRenderer::New(NDS->GPU);
+ glrenderer->SetRenderSettings(Config::GL_BetterPolygons, Config::GL_ScaleFactor);
+ NDS->GPU.SetRenderer3D(std::move(glrenderer));
+ }
}
// process input and hotkeys
@@ -804,10 +815,10 @@ void EmuThread::drawScreenGL()
glActiveTexture(GL_TEXTURE0);
#ifdef OGLRENDERER_ENABLED
- if (NDS->GPU.Renderer != 0)
+ if (NDS->GPU.GetRenderer3D().Accelerated)
{
// hardware-accelerated render
- NDS->GPU.CurGLCompositor->BindOutputTexture(frontbuf);
+ static_cast<GLRenderer&>(NDS->GPU.GetRenderer3D()).GetCompositor().BindOutputTexture(frontbuf);
}
else
#endif
@@ -818,9 +829,9 @@ void EmuThread::drawScreenGL()
if (NDS->GPU.Framebuffer[frontbuf][0] && NDS->GPU.Framebuffer[frontbuf][1])
{
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA,
- GL_UNSIGNED_BYTE, NDS->GPU.Framebuffer[frontbuf][0]);
+ GL_UNSIGNED_BYTE, NDS->GPU.Framebuffer[frontbuf][0].get());
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 192+2, 256, 192, GL_RGBA,
- GL_UNSIGNED_BYTE, NDS->GPU.Framebuffer[frontbuf][1]);
+ GL_UNSIGNED_BYTE, NDS->GPU.Framebuffer[frontbuf][1].get());
}
}
@@ -1122,8 +1133,8 @@ void ScreenPanelNative::paintEvent(QPaintEvent* event)
return;
}
- memcpy(screen[0].scanLine(0), emuThread->NDS->GPU.Framebuffer[frontbuf][0], 256 * 192 * 4);
- memcpy(screen[1].scanLine(0), emuThread->NDS->GPU.Framebuffer[frontbuf][1], 256 * 192 * 4);
+ memcpy(screen[0].scanLine(0), emuThread->NDS->GPU.Framebuffer[frontbuf][0].get(), 256 * 192 * 4);
+ memcpy(screen[1].scanLine(0), emuThread->NDS->GPU.Framebuffer[frontbuf][1].get(), 256 * 192 * 4);
emuThread->FrontBufferLock.unlock();
QRect screenrc(0, 0, 256, 192);
diff --git a/src/types.h b/src/types.h
index d37b225..86a10aa 100644
--- a/src/types.h
+++ b/src/types.h
@@ -20,6 +20,7 @@
#define TYPES_H
#include <stdint.h>
+#include <array>
namespace melonDS
{
@@ -32,5 +33,7 @@ typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
+template<class T, std::size_t A, std::size_t B>
+using array2d = std::array<std::array<T, B>, A>;
}
#endif // TYPES_H