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:
parent
e973236203
commit
7caddf9615
150
src/GPU.cpp
150
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] = 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
36
src/GPU.h
36
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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{ }
|
||||
|
|
16
src/GPU3D.h
16
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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {};
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue