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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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();
}
}

View File

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

View File

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

View File

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

View File

@ -49,12 +49,74 @@ private:
u32 NumSprites[2];
u8* CurBGXMosaicTable;
u8 MosaicTable[16][256];
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;
}
}
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<u32 bgmode> void DrawScanlineBGMode(u32 line);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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