From 7caddf9615875e54b725bd7df266361c46d47b6f Mon Sep 17 00:00:00 2001 From: Jesse Talavera-Greenberg Date: Wed, 29 Nov 2023 09:23:11 -0500 Subject: [PATCH] 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` --- src/GPU.cpp | 150 +++++++---------------------------- src/GPU.h | 36 +++------ src/GPU2D.h | 2 +- src/GPU2D_Soft.cpp | 71 ++--------------- src/GPU2D_Soft.h | 72 +++++++++++++++-- src/GPU3D.cpp | 17 +++- src/GPU3D.h | 16 ++-- src/GPU3D_OpenGL.cpp | 43 ++++++++-- src/GPU3D_OpenGL.h | 28 ++++--- src/GPU3D_Soft.cpp | 14 ++-- src/GPU3D_Soft.h | 47 +++++------ src/GPU_OpenGL.cpp | 110 +++++++++++++++++++------ src/GPU_OpenGL.h | 46 +++++------ src/frontend/qt_sdl/main.cpp | 45 +++++++---- src/types.h | 3 + 15 files changed, 366 insertions(+), 334 deletions(-) diff --git a/src/GPU.cpp b/src/GPU.cpp index 7a81f7dd..c80e3119 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, std::unique_ptr&& renderer2d) noexcept : + NDS(nds), + GPU2D_A(0, *this), + GPU2D_B(1, *this), + GPU3D(nds, renderer3d ? std::move(renderer3d) : std::make_unique(*this)), + GPU2D_Renderer(renderer2d ? std::move(renderer2d) : std::make_unique(*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(*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&& 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(*this)); - } - GPU3D.SetCurrentRenderer(GLRenderer::New(*this)); - if (!GPU3D.GetCurrentRenderer()) - { - // Fallback on software renderer - CurGLCompositor.reset(); - renderer = 0; - GPU3D.SetCurrentRenderer(std::make_unique(*this)); - } - } - else -#endif - { + if (renderer == nullptr) GPU3D.SetCurrentRenderer(std::make_unique(*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(fbsize); + Framebuffer[1][0] = std::make_unique(fbsize); + Framebuffer[0][1] = std::make_unique(fbsize); + Framebuffer[1][1] = std::make_unique(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(); } } diff --git a/src/GPU.h b/src/GPU.h index 84210c9d..21a05d58 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 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 = nullptr, std::unique_ptr&& 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&& 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&& 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 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 CurGLCompositor = nullptr; -#endif private: void ResetVRAMCache() noexcept; void AssignFramebuffers() noexcept; diff --git a/src/GPU2D.h b/src/GPU2D.h index dd3bbf6b..7367d07a 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 9e7d8491..6d0252c3 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(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 86943d33..ca242a51 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]; + array2d MosaicTable = []() constexpr + { + array2d 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; + } + } - 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); + 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 void DrawScanlineBGMode(u32 line); diff --git a/src/GPU3D.cpp b/src/GPU3D.cpp index 5603a136..049ae589 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&& renderer) noexcept : + NDS(nds), + CurrentRenderer(renderer ? std::move(renderer) : std::make_unique(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 1d3e1265..8e743fac 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&& 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&& 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 fb9f2461..bee04305 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::New(melonDS::GPU& gpu) noexcept { assert(glEnable != nullptr); + std::optional 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 result = std::unique_ptr(new GLRenderer(gpu)); + std::unique_ptr result = std::unique_ptr(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::SetRenderSettings(const RenderSettings& settings) noexcept +void GLRenderer::SetBetterPolygons(bool betterpolygons) noexcept { - int scale = settings.GL_ScaleFactor; + SetRenderSettings(betterpolygons, ScaleFactor); +} +void GLRenderer::SetScaleFactor(int scale) noexcept +{ + 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 0bc20d81..63ee8de2 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 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 809bd593..03c6265e 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 9fb9a718..2f5664e2 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 - 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 - void EdgeParams_YMajor(s32* length, s32* coverage) + constexpr void EdgeParams_YMajor(s32* length, s32* coverage) const { *length = 1; @@ -404,7 +405,7 @@ private: } template - void EdgeParams(s32* length, s32* coverage) + constexpr void EdgeParams(s32* length, s32* coverage) const { if (XMajor) return EdgeParams_XMajor(length, coverage); diff --git a/src/GPU_OpenGL.cpp b/src/GPU_OpenGL.cpp index 2db38105..2e2857ce 100644 --- a/src/GPU_OpenGL.cpp +++ b/src/GPU_OpenGL.cpp @@ -33,13 +33,13 @@ namespace melonDS using namespace OpenGL; -std::unique_ptr GLCompositor::New(melonDS::GPU& gpu) noexcept +std::optional GLCompositor::New() noexcept { assert(glBindAttribLocation != nullptr); std::array 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::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(new GLCompositor(CompShader, gpu)); + return { GLCompositor(CompShader) }; } -GLCompositor::GLCompositor(std::array compShader, melonDS::GPU& gpu) noexcept : CompShader(compShader), GPU(gpu) +GLCompositor::GLCompositor(std::array compShader) noexcept : CompShader(compShader) { CompScaleLoc = glGetUniformLocation(CompShader[2], "u3DScale"); Comp3DXPosLoc = glGetUniformLocation(CompShader[2], "u3DXPos"); @@ -92,7 +92,7 @@ GLCompositor::GLCompositor(std::array 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 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 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(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 68462a9a..9c040966 100644 --- a/src/GPU_OpenGL.h +++ b/src/GPU_OpenGL.h @@ -21,51 +21,51 @@ #include "OpenGLSupport.h" #include -#include +#include namespace melonDS { class GPU; struct RenderSettings; - +class GLRenderer; class GLCompositor { public: - static std::unique_ptr New(melonDS::GPU& gpu) noexcept; + static std::optional New() noexcept; GLCompositor(const GLCompositor&) = delete; GLCompositor& operator=(const GLCompositor&) = delete; + GLCompositor(GLCompositor&&) noexcept; + GLCompositor& operator=(GLCompositor&&) noexcept; ~GLCompositor(); - void Reset(); + void SetScaleFactor(int scale) noexcept; + [[nodiscard]] int GetScaleFactor() const noexcept { return Scale; } - void SetRenderSettings(const RenderSettings& settings) noexcept; - - 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 CompShader, melonDS::GPU& gpu) noexcept; - melonDS::GPU& GPU; - int Scale; - int ScreenH, ScreenW; + GLCompositor(std::array CompShader) noexcept; + int Scale = 0; + int ScreenH = 0, ScreenW = 0; - std::array CompShader; - GLuint CompScaleLoc; - GLuint Comp3DXPosLoc; + std::array 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 Position {}; + std::array Texcoord {}; }; - CompVertex CompVertices[2 * 3*2]; + std::array CompVertices {}; - GLuint CompScreenInputTex; - GLuint CompScreenOutputTex[2]; - GLuint CompScreenOutputFB[2]; + GLuint CompScreenInputTex = 0; + std::array CompScreenOutputTex {}; + std::array CompScreenOutputFB {}; }; } diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index 54a6f14f..a0ac0860 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(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(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(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 d37b2251..86a10aa7 100644 --- a/src/types.h +++ b/src/types.h @@ -20,6 +20,7 @@ #define TYPES_H #include +#include namespace melonDS { @@ -32,5 +33,7 @@ typedef int16_t s16; typedef int32_t s32; typedef int64_t s64; +template +using array2d = std::array, A>; } #endif // TYPES_H