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 "GPU2D_Soft.h"
|
||||||
#include "GPU3D_Soft.h"
|
#include "GPU3D_Soft.h"
|
||||||
#include "GPU3D_OpenGL.h"
|
|
||||||
|
|
||||||
namespace melonDS
|
namespace melonDS
|
||||||
{
|
{
|
||||||
|
@ -64,33 +63,24 @@ enum
|
||||||
VRAMDirty need to be reset for the respective VRAM bank.
|
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_StartHBlank, MemberEventFunc(GPU, StartHBlank));
|
||||||
NDS.RegisterEventFunc(Event_LCD, LCD_StartScanline, MemberEventFunc(GPU, StartScanline));
|
NDS.RegisterEventFunc(Event_LCD, LCD_StartScanline, MemberEventFunc(GPU, StartScanline));
|
||||||
NDS.RegisterEventFunc(Event_LCD, LCD_FinishFrame, MemberEventFunc(GPU, FinishFrame));
|
NDS.RegisterEventFunc(Event_LCD, LCD_FinishFrame, MemberEventFunc(GPU, FinishFrame));
|
||||||
NDS.RegisterEventFunc(Event_DisplayFIFO, 0, MemberEventFunc(GPU, DisplayFIFO));
|
NDS.RegisterEventFunc(Event_DisplayFIFO, 0, MemberEventFunc(GPU, DisplayFIFO));
|
||||||
|
|
||||||
GPU2D_Renderer = std::make_unique<GPU2D::SoftRenderer>(*this);
|
|
||||||
|
|
||||||
FrontBuffer = 0;
|
FrontBuffer = 0;
|
||||||
Framebuffer[0][0] = NULL; Framebuffer[0][1] = NULL;
|
|
||||||
Framebuffer[1][0] = NULL; Framebuffer[1][1] = NULL;
|
|
||||||
Renderer = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GPU::~GPU() noexcept
|
GPU::~GPU() noexcept
|
||||||
{
|
{
|
||||||
// All unique_ptr fields are automatically cleaned up
|
// 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_StartHBlank);
|
||||||
NDS.UnregisterEventFunc(Event_LCD, LCD_StartScanline);
|
NDS.UnregisterEventFunc(Event_LCD, LCD_StartScanline);
|
||||||
|
@ -198,9 +188,7 @@ void GPU::Reset() noexcept
|
||||||
GPU3D.Reset();
|
GPU3D.Reset();
|
||||||
|
|
||||||
int backbuf = FrontBuffer ? 0 : 1;
|
int backbuf = FrontBuffer ? 0 : 1;
|
||||||
GPU2D_Renderer->SetFramebuffer(Framebuffer[backbuf][1], Framebuffer[backbuf][0]);
|
GPU2D_Renderer->SetFramebuffer(Framebuffer[backbuf][1].get(), Framebuffer[backbuf][0].get());
|
||||||
|
|
||||||
ResetRenderer();
|
|
||||||
|
|
||||||
ResetVRAMCache();
|
ResetVRAMCache();
|
||||||
|
|
||||||
|
@ -216,17 +204,12 @@ void GPU::Stop() noexcept
|
||||||
else
|
else
|
||||||
fbsize = 256 * 192;
|
fbsize = 256 * 192;
|
||||||
|
|
||||||
memset(Framebuffer[0][0], 0, fbsize*4);
|
memset(Framebuffer[0][0].get(), 0, fbsize*4);
|
||||||
memset(Framebuffer[0][1], 0, fbsize*4);
|
memset(Framebuffer[0][1].get(), 0, fbsize*4);
|
||||||
memset(Framebuffer[1][0], 0, fbsize*4);
|
memset(Framebuffer[1][0].get(), 0, fbsize*4);
|
||||||
memset(Framebuffer[1][1], 0, fbsize*4);
|
memset(Framebuffer[1][1].get(), 0, fbsize*4);
|
||||||
|
|
||||||
#ifdef OGLRENDERER_ENABLED
|
GPU3D.Stop();
|
||||||
// This needs a better way to know that we're
|
|
||||||
// using the OpenGL renderer specifically
|
|
||||||
if (GPU3D.IsRendererAccelerated())
|
|
||||||
CurGLCompositor->Stop();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU::DoSavestate(Savestate* file) noexcept
|
void GPU::DoSavestate(Savestate* file) noexcept
|
||||||
|
@ -300,78 +283,20 @@ void GPU::AssignFramebuffers() noexcept
|
||||||
int backbuf = FrontBuffer ? 0 : 1;
|
int backbuf = FrontBuffer ? 0 : 1;
|
||||||
if (NDS.PowerControl9 & (1<<15))
|
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
|
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 == nullptr)
|
||||||
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(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
|
else
|
||||||
#endif
|
GPU3D.SetCurrentRenderer(std::move(renderer));
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fbsize;
|
int fbsize;
|
||||||
if (GPU3D.IsRendererAccelerated())
|
if (GPU3D.IsRendererAccelerated())
|
||||||
|
@ -379,34 +304,17 @@ void GPU::SetRenderSettings(int renderer, RenderSettings& settings) noexcept
|
||||||
else
|
else
|
||||||
fbsize = 256 * 192;
|
fbsize = 256 * 192;
|
||||||
|
|
||||||
if (Framebuffer[0][0]) { delete[] Framebuffer[0][0]; Framebuffer[0][0] = nullptr; }
|
Framebuffer[0][0] = std::make_unique<u32[]>(fbsize);
|
||||||
if (Framebuffer[1][0]) { delete[] Framebuffer[1][0]; Framebuffer[1][0] = nullptr; }
|
Framebuffer[1][0] = std::make_unique<u32[]>(fbsize);
|
||||||
if (Framebuffer[0][1]) { delete[] Framebuffer[0][1]; Framebuffer[0][1] = nullptr; }
|
Framebuffer[0][1] = std::make_unique<u32[]>(fbsize);
|
||||||
if (Framebuffer[1][1]) { delete[] Framebuffer[1][1]; Framebuffer[1][1] = nullptr; }
|
Framebuffer[1][1] = std::make_unique<u32[]>(fbsize);
|
||||||
|
|
||||||
Framebuffer[0][0] = new u32[fbsize];
|
memset(Framebuffer[0][0].get(), 0, fbsize*4);
|
||||||
Framebuffer[1][0] = new u32[fbsize];
|
memset(Framebuffer[1][0].get(), 0, fbsize*4);
|
||||||
Framebuffer[0][1] = new u32[fbsize];
|
memset(Framebuffer[0][1].get(), 0, fbsize*4);
|
||||||
Framebuffer[1][1] = new u32[fbsize];
|
memset(Framebuffer[1][1].get(), 0, fbsize*4);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
AssignFramebuffers();
|
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
|
else
|
||||||
fbsize = 256 * 192;
|
fbsize = 256 * 192;
|
||||||
|
|
||||||
memset(Framebuffer[backbuf][0], 0, fbsize*4);
|
memset(Framebuffer[backbuf][0].get(), 0, fbsize*4);
|
||||||
memset(Framebuffer[backbuf][1], 0, fbsize*4);
|
memset(Framebuffer[backbuf][1].get(), 0, fbsize*4);
|
||||||
|
|
||||||
FrontBuffer = backbuf;
|
FrontBuffer = backbuf;
|
||||||
AssignFramebuffers();
|
AssignFramebuffers();
|
||||||
|
@ -1123,11 +1031,9 @@ void GPU::StartScanline(u32 line) noexcept
|
||||||
GPU2D_B.VBlank();
|
GPU2D_B.VBlank();
|
||||||
GPU3D.VBlank();
|
GPU3D.VBlank();
|
||||||
|
|
||||||
#ifdef OGLRENDERER_ENABLED
|
|
||||||
// Need a better way to identify the openGL renderer in particular
|
// Need a better way to identify the openGL renderer in particular
|
||||||
if (GPU3D.IsRendererAccelerated())
|
if (GPU3D.IsRendererAccelerated())
|
||||||
CurGLCompositor->RenderFrame();
|
GPU3D.Blit();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
36
src/GPU.h
36
src/GPU.h
|
@ -25,10 +25,6 @@
|
||||||
#include "GPU3D.h"
|
#include "GPU3D.h"
|
||||||
#include "NonStupidBitfield.h"
|
#include "NonStupidBitfield.h"
|
||||||
|
|
||||||
#ifdef OGLRENDERER_ENABLED
|
|
||||||
#include "GPU_OpenGL.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace melonDS
|
namespace melonDS
|
||||||
{
|
{
|
||||||
class GPU3D;
|
class GPU3D;
|
||||||
|
@ -56,33 +52,30 @@ struct VRAMTrackingSet
|
||||||
NonStupidBitField<Size/VRAMDirtyGranularity> DeriveState(u32* currentMappings, GPU& gpu);
|
NonStupidBitField<Size/VRAMDirtyGranularity> DeriveState(u32* currentMappings, GPU& gpu);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RenderSettings
|
|
||||||
{
|
|
||||||
bool Soft_Threaded;
|
|
||||||
|
|
||||||
int GL_ScaleFactor;
|
|
||||||
bool GL_BetterPolygons;
|
|
||||||
};
|
|
||||||
|
|
||||||
class GPU
|
class GPU
|
||||||
{
|
{
|
||||||
public:
|
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;
|
~GPU() noexcept;
|
||||||
void Reset() noexcept;
|
void Reset() noexcept;
|
||||||
void Stop() noexcept;
|
void Stop() noexcept;
|
||||||
|
|
||||||
void DoSavestate(Savestate* file) noexcept;
|
void DoSavestate(Savestate* file) noexcept;
|
||||||
|
|
||||||
[[deprecated("Set the renderer directly instead of using an integer code")]] void InitRenderer(int renderer) noexcept;
|
/// Sets the active renderer to the renderer given in the provided pointer.
|
||||||
void DeInitRenderer() noexcept;
|
/// The pointer is moved-from, so it will be \c nullptr after this method is called.
|
||||||
void ResetRenderer() noexcept;
|
/// If the pointer is \c nullptr, the renderer is reset to the default renderer.
|
||||||
|
void SetRenderer3D(std::unique_ptr<Renderer3D>&& renderer) noexcept;
|
||||||
void SetRenderSettings(int renderer, RenderSettings& settings) noexcept;
|
[[nodiscard]] const Renderer3D& GetRenderer3D() const noexcept { return GPU3D.GetCurrentRenderer(); }
|
||||||
|
[[nodiscard]] Renderer3D& GetRenderer3D() noexcept { return GPU3D.GetCurrentRenderer(); }
|
||||||
|
|
||||||
u8* GetUniqueBankPtr(u32 mask, u32 offset) noexcept;
|
u8* GetUniqueBankPtr(u32 mask, u32 offset) noexcept;
|
||||||
const u8* GetUniqueBankPtr(u32 mask, u32 offset) const 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_AB(u32 bank, u8 cnt) noexcept;
|
||||||
void MapVRAM_CD(u32 bank, u8 cnt) noexcept;
|
void MapVRAM_CD(u32 bank, u8 cnt) noexcept;
|
||||||
void MapVRAM_E(u32 bank, u8 cnt) noexcept;
|
void MapVRAM_E(u32 bank, u8 cnt) noexcept;
|
||||||
|
@ -578,7 +571,7 @@ public:
|
||||||
u8* VRAMPtr_BOBJ[0x8] {};
|
u8* VRAMPtr_BOBJ[0x8] {};
|
||||||
|
|
||||||
int FrontBuffer = 0;
|
int FrontBuffer = 0;
|
||||||
u32* Framebuffer[2][2] {};
|
std::unique_ptr<u32[]> Framebuffer[2][2] {};
|
||||||
|
|
||||||
GPU2D::Unit GPU2D_A;
|
GPU2D::Unit GPU2D_A;
|
||||||
GPU2D::Unit GPU2D_B;
|
GPU2D::Unit GPU2D_B;
|
||||||
|
@ -611,11 +604,6 @@ public:
|
||||||
|
|
||||||
u8 VRAMFlat_Texture[512*1024] {};
|
u8 VRAMFlat_Texture[512*1024] {};
|
||||||
u8 VRAMFlat_TexPal[128*1024] {};
|
u8 VRAMFlat_TexPal[128*1024] {};
|
||||||
|
|
||||||
int Renderer = 0;
|
|
||||||
#ifdef OGLRENDERER_ENABLED
|
|
||||||
std::unique_ptr<GLCompositor> CurGLCompositor = nullptr;
|
|
||||||
#endif
|
|
||||||
private:
|
private:
|
||||||
void ResetVRAMCache() noexcept;
|
void ResetVRAMCache() noexcept;
|
||||||
void AssignFramebuffers() noexcept;
|
void AssignFramebuffers() noexcept;
|
||||||
|
|
|
@ -35,7 +35,7 @@ public:
|
||||||
// take a reference to the GPU so we can access its state
|
// take a reference to the GPU so we can access its state
|
||||||
// and ensure that it's not null
|
// and ensure that it's not null
|
||||||
Unit(u32 num, melonDS::GPU& gpu);
|
Unit(u32 num, melonDS::GPU& gpu);
|
||||||
|
virtual ~Unit() = default;
|
||||||
Unit(const Unit&) = delete;
|
Unit(const Unit&) = delete;
|
||||||
Unit& operator=(const Unit&) = delete;
|
Unit& operator=(const Unit&) = delete;
|
||||||
|
|
||||||
|
|
|
@ -27,68 +27,7 @@ namespace GPU2D
|
||||||
SoftRenderer::SoftRenderer(melonDS::GPU& gpu)
|
SoftRenderer::SoftRenderer(melonDS::GPU& gpu)
|
||||||
: Renderer2D(), GPU(gpu)
|
: Renderer2D(), GPU(gpu)
|
||||||
{
|
{
|
||||||
// initialize mosaic table
|
// mosaic table is initialized at compile-time
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 SoftRenderer::ColorComposite(int i, u32 val1, u32 val2)
|
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)
|
void SoftRenderer::VBlankEnd(Unit* unitA, Unit* unitB)
|
||||||
{
|
{
|
||||||
#ifdef OGLRENDERER_ENABLED
|
#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))
|
if ((unitA->CaptureCnt & (1<<31)) && (((unitA->CaptureCnt >> 29) & 0x3) != 1))
|
||||||
{
|
{
|
||||||
reinterpret_cast<GLRenderer*>(GPU.GPU3D.GetCurrentRenderer())->PrepareCaptureFrame();
|
renderer3d.PrepareCaptureFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -779,7 +718,7 @@ void SoftRenderer::DrawScanline_BGOBJ(u32 line)
|
||||||
memset(WindowMask, 0xFF, 256);
|
memset(WindowMask, 0xFF, 256);
|
||||||
|
|
||||||
ApplySpriteMosaicX();
|
ApplySpriteMosaicX();
|
||||||
CurBGXMosaicTable = MosaicTable[CurUnit->BGMosaicSize[0]];
|
CurBGXMosaicTable = MosaicTable[CurUnit->BGMosaicSize[0]].data();
|
||||||
|
|
||||||
switch (CurUnit->DispCnt & 0x7)
|
switch (CurUnit->DispCnt & 0x7)
|
||||||
{
|
{
|
||||||
|
@ -1564,7 +1503,7 @@ void SoftRenderer::ApplySpriteMosaicX()
|
||||||
|
|
||||||
u32* objLine = OBJLine[CurUnit->Num];
|
u32* objLine = OBJLine[CurUnit->Num];
|
||||||
|
|
||||||
u8* curOBJXMosaicTable = MosaicTable[CurUnit->OBJMosaicSize[1]];
|
u8* curOBJXMosaicTable = MosaicTable[CurUnit->OBJMosaicSize[1]].data();
|
||||||
|
|
||||||
u32 lastcolor = objLine[0];
|
u32 lastcolor = objLine[0];
|
||||||
|
|
||||||
|
|
|
@ -49,12 +49,74 @@ private:
|
||||||
u32 NumSprites[2];
|
u32 NumSprites[2];
|
||||||
|
|
||||||
u8* CurBGXMosaicTable;
|
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);
|
return table;
|
||||||
u32 ColorBlend5(u32 val1, u32 val2);
|
}();
|
||||||
u32 ColorBrightnessUp(u32 val, u32 factor, u32 bias);
|
|
||||||
u32 ColorBrightnessDown(u32 val, u32 factor, u32 bias);
|
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);
|
u32 ColorComposite(int i, u32 val1, u32 val2);
|
||||||
|
|
||||||
template<u32 bgmode> void DrawScanlineBGMode(u32 line);
|
template<u32 bgmode> void DrawScanlineBGMode(u32 line);
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "NDS.h"
|
#include "NDS.h"
|
||||||
#include "GPU.h"
|
#include "GPU.h"
|
||||||
#include "FIFO.h"
|
#include "FIFO.h"
|
||||||
|
#include "GPU3D_Soft.h"
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
|
|
||||||
namespace melonDS
|
namespace melonDS
|
||||||
|
@ -139,7 +140,9 @@ const u8 CmdNumParams[256] =
|
||||||
|
|
||||||
void MatrixLoadIdentity(s32* m);
|
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();
|
CurrentRenderer->RestartFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GPU3D::Stop() noexcept
|
||||||
|
{
|
||||||
|
if (CurrentRenderer)
|
||||||
|
CurrentRenderer->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool YSort(Polygon* a, Polygon* b)
|
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);
|
Log(LogLevel::Debug, "unknown GPU3D write32 %08X %08X\n", addr, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GPU3D::Blit() noexcept
|
||||||
|
{
|
||||||
|
if (CurrentRenderer)
|
||||||
|
CurrentRenderer->Blit();
|
||||||
|
}
|
||||||
|
|
||||||
Renderer3D::Renderer3D(bool Accelerated)
|
Renderer3D::Renderer3D(bool Accelerated)
|
||||||
: Accelerated(Accelerated)
|
: Accelerated(Accelerated)
|
||||||
{ }
|
{ }
|
||||||
|
|
16
src/GPU3D.h
16
src/GPU3D.h
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
namespace melonDS
|
namespace melonDS
|
||||||
{
|
{
|
||||||
struct RenderSettings;
|
class GPU;
|
||||||
|
|
||||||
struct Vertex
|
struct Vertex
|
||||||
{
|
{
|
||||||
|
@ -86,7 +86,7 @@ class NDS;
|
||||||
class GPU3D
|
class GPU3D
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GPU3D(melonDS::NDS& nds) noexcept;
|
GPU3D(melonDS::NDS& nds, std::unique_ptr<Renderer3D>&& renderer = nullptr) noexcept;
|
||||||
~GPU3D() noexcept = default;
|
~GPU3D() noexcept = default;
|
||||||
void Reset() noexcept;
|
void Reset() noexcept;
|
||||||
|
|
||||||
|
@ -106,6 +106,7 @@ public:
|
||||||
void VCount215() noexcept;
|
void VCount215() noexcept;
|
||||||
|
|
||||||
void RestartFrame() noexcept;
|
void RestartFrame() noexcept;
|
||||||
|
void Stop() noexcept;
|
||||||
|
|
||||||
void SetRenderXPos(u16 xpos) noexcept;
|
void SetRenderXPos(u16 xpos) noexcept;
|
||||||
[[nodiscard]] u16 GetRenderXPos() const noexcept { return RenderXPos; }
|
[[nodiscard]] u16 GetRenderXPos() const noexcept { return RenderXPos; }
|
||||||
|
@ -114,8 +115,8 @@ public:
|
||||||
void WriteToGXFIFO(u32 val) noexcept;
|
void WriteToGXFIFO(u32 val) noexcept;
|
||||||
|
|
||||||
[[nodiscard]] bool IsRendererAccelerated() const noexcept;
|
[[nodiscard]] bool IsRendererAccelerated() const noexcept;
|
||||||
[[nodiscard]] Renderer3D* GetCurrentRenderer() noexcept { return CurrentRenderer.get(); }
|
[[nodiscard]] Renderer3D& GetCurrentRenderer() noexcept { return *CurrentRenderer; }
|
||||||
[[nodiscard]] const Renderer3D* GetCurrentRenderer() const noexcept { return CurrentRenderer.get(); }
|
[[nodiscard]] const Renderer3D& GetCurrentRenderer() const noexcept { return *CurrentRenderer; }
|
||||||
void SetCurrentRenderer(std::unique_ptr<Renderer3D>&& renderer) noexcept { CurrentRenderer = std::move(renderer); }
|
void SetCurrentRenderer(std::unique_ptr<Renderer3D>&& renderer) noexcept { CurrentRenderer = std::move(renderer); }
|
||||||
|
|
||||||
u8 Read8(u32 addr) noexcept;
|
u8 Read8(u32 addr) noexcept;
|
||||||
|
@ -124,6 +125,7 @@ public:
|
||||||
void Write8(u32 addr, u8 val) noexcept;
|
void Write8(u32 addr, u8 val) noexcept;
|
||||||
void Write16(u32 addr, u16 val) noexcept;
|
void Write16(u32 addr, u16 val) noexcept;
|
||||||
void Write32(u32 addr, u32 val) noexcept;
|
void Write32(u32 addr, u32 val) noexcept;
|
||||||
|
void Blit() noexcept;
|
||||||
private:
|
private:
|
||||||
melonDS::NDS& NDS;
|
melonDS::NDS& NDS;
|
||||||
typedef union
|
typedef union
|
||||||
|
@ -338,13 +340,13 @@ public:
|
||||||
// are more detailed "traits" that we can ask of the Renderer3D type
|
// are more detailed "traits" that we can ask of the Renderer3D type
|
||||||
const bool Accelerated;
|
const bool Accelerated;
|
||||||
|
|
||||||
virtual void SetRenderSettings(const RenderSettings& settings) noexcept = 0;
|
|
||||||
|
|
||||||
virtual void VCount144() {};
|
virtual void VCount144() {};
|
||||||
|
virtual void Stop() {}
|
||||||
virtual void RenderFrame() = 0;
|
virtual void RenderFrame() = 0;
|
||||||
virtual void RestartFrame() {};
|
virtual void RestartFrame() {};
|
||||||
virtual u32* GetLine(int line) = 0;
|
virtual u32* GetLine(int line) = 0;
|
||||||
|
virtual void Blit() {};
|
||||||
|
virtual void PrepareCaptureFrame() {}
|
||||||
protected:
|
protected:
|
||||||
Renderer3D(bool Accelerated);
|
Renderer3D(bool Accelerated);
|
||||||
};
|
};
|
||||||
|
|
|
@ -97,7 +97,10 @@ void SetupDefaultTexParams(GLuint tex)
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
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;
|
// GLRenderer::New() will be used to actually initialize the renderer;
|
||||||
// The various glDelete* functions silently ignore invalid IDs,
|
// 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);
|
assert(glEnable != nullptr);
|
||||||
|
|
||||||
|
std::optional<GLCompositor> compositor = GLCompositor::New();
|
||||||
|
if (!compositor)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
// Will be returned if the initialization succeeds,
|
// Will be returned if the initialization succeeds,
|
||||||
// or cleaned up via RAII if it fails.
|
// 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_DEPTH_TEST);
|
||||||
glEnable(GL_STENCIL_TEST);
|
glEnable(GL_STENCIL_TEST);
|
||||||
|
@ -327,14 +335,29 @@ GLRenderer::~GLRenderer()
|
||||||
|
|
||||||
void GLRenderer::Reset()
|
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;
|
ScaleFactor = scale;
|
||||||
BetterPolygons = settings.GL_BetterPolygons;
|
BetterPolygons = betterpolygons;
|
||||||
|
|
||||||
ScreenW = 256 * scale;
|
ScreenW = 256 * scale;
|
||||||
ScreenH = 192 * scale;
|
ScreenH = 192 * scale;
|
||||||
|
@ -1302,6 +1325,11 @@ void GLRenderer::RenderFrame()
|
||||||
FrontBuffer = FrontBuffer ? 0 : 1;
|
FrontBuffer = FrontBuffer ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLRenderer::Stop()
|
||||||
|
{
|
||||||
|
CurGLCompositor.Stop(GPU);
|
||||||
|
}
|
||||||
|
|
||||||
void GLRenderer::PrepareCaptureFrame()
|
void GLRenderer::PrepareCaptureFrame()
|
||||||
{
|
{
|
||||||
// TODO: make sure this picks the right buffer when doing antialiasing
|
// 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);
|
glReadPixels(0, 0, 256, 192, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLRenderer::Blit()
|
||||||
|
{
|
||||||
|
CurGLCompositor.RenderFrame(GPU, *this);
|
||||||
|
}
|
||||||
|
|
||||||
u32* GLRenderer::GetLine(int line)
|
u32* GLRenderer::GetLine(int line)
|
||||||
{
|
{
|
||||||
int stride = 256;
|
int stride = 256;
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
#ifdef OGLRENDERER_ENABLED
|
#ifdef OGLRENDERER_ENABLED
|
||||||
#include "GPU3D.h"
|
#include "GPU3D.h"
|
||||||
|
#include "GPU_OpenGL.h"
|
||||||
#include "OpenGLSupport.h"
|
#include "OpenGLSupport.h"
|
||||||
|
|
||||||
namespace melonDS
|
namespace melonDS
|
||||||
|
@ -30,22 +30,31 @@ class GPU;
|
||||||
class GLRenderer : public Renderer3D
|
class GLRenderer : public Renderer3D
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~GLRenderer() override;
|
~GLRenderer() override;
|
||||||
virtual void Reset() 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 {};
|
void VCount144() override {};
|
||||||
virtual void RenderFrame() override;
|
void RenderFrame() override;
|
||||||
virtual u32* GetLine(int line) override;
|
void Stop() override;
|
||||||
|
u32* GetLine(int line) override;
|
||||||
|
|
||||||
void SetupAccelFrame();
|
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;
|
static std::unique_ptr<GLRenderer> New(melonDS::GPU& gpu) noexcept;
|
||||||
private:
|
private:
|
||||||
// Used by New()
|
// Used by New()
|
||||||
GLRenderer(melonDS::GPU& gpu) noexcept;
|
GLRenderer(GLCompositor&& compositor, GPU& gpu) noexcept;
|
||||||
|
|
||||||
// GL version requirements
|
// GL version requirements
|
||||||
// * texelFetch: 3.0 (GLSL 1.30) (3.2/1.50 for MS)
|
// * texelFetch: 3.0 (GLSL 1.30) (3.2/1.50 for MS)
|
||||||
|
@ -66,6 +75,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
melonDS::GPU& GPU;
|
melonDS::GPU& GPU;
|
||||||
|
GLCompositor CurGLCompositor;
|
||||||
RendererPolygon PolygonList[2048] {};
|
RendererPolygon PolygonList[2048] {};
|
||||||
|
|
||||||
bool BuildRenderShader(u32 flags, const char* vs, const char* fs);
|
bool BuildRenderShader(u32 flags, const char* vs, const char* fs);
|
||||||
|
|
|
@ -71,14 +71,13 @@ void SoftRenderer::SetupRenderThread()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SoftRenderer::SoftRenderer(melonDS::GPU& gpu) noexcept
|
SoftRenderer::SoftRenderer(melonDS::GPU& gpu, bool threaded) noexcept
|
||||||
: Renderer3D(false), GPU(gpu)
|
: Renderer3D(false), GPU(gpu), Threaded(threaded)
|
||||||
{
|
{
|
||||||
Sema_RenderStart = Platform::Semaphore_Create();
|
Sema_RenderStart = Platform::Semaphore_Create();
|
||||||
Sema_RenderDone = Platform::Semaphore_Create();
|
Sema_RenderDone = Platform::Semaphore_Create();
|
||||||
Sema_ScanlineCount = Platform::Semaphore_Create();
|
Sema_ScanlineCount = Platform::Semaphore_Create();
|
||||||
|
|
||||||
Threaded = false;
|
|
||||||
RenderThreadRunning = false;
|
RenderThreadRunning = false;
|
||||||
RenderThreadRendering = false;
|
RenderThreadRendering = false;
|
||||||
RenderThread = nullptr;
|
RenderThread = nullptr;
|
||||||
|
@ -104,10 +103,13 @@ void SoftRenderer::Reset()
|
||||||
SetupRenderThread();
|
SetupRenderThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftRenderer::SetRenderSettings(const RenderSettings& settings) noexcept
|
void SoftRenderer::SetThreaded(bool threaded) noexcept
|
||||||
{
|
{
|
||||||
Threaded = settings.Soft_Threaded;
|
if (Threaded != threaded)
|
||||||
|
{
|
||||||
|
Threaded = threaded;
|
||||||
SetupRenderThread();
|
SetupRenderThread();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoftRenderer::TextureLookup(u32 texparam, u32 texpal, s16 s, s16 t, u16* color, u8* alpha)
|
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
|
class SoftRenderer : public Renderer3D
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SoftRenderer(melonDS::GPU& gpu) noexcept;
|
SoftRenderer(melonDS::GPU& gpu, bool threaded = false) noexcept;
|
||||||
virtual ~SoftRenderer() override;
|
~SoftRenderer() override;
|
||||||
virtual void Reset() 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;
|
void VCount144() override;
|
||||||
virtual void RenderFrame() override;
|
void RenderFrame() override;
|
||||||
virtual void RestartFrame() override;
|
void RestartFrame() override;
|
||||||
virtual u32* GetLine(int line) override;
|
u32* GetLine(int line) override;
|
||||||
|
|
||||||
void SetupRenderThread();
|
void SetupRenderThread();
|
||||||
void StopRenderThread();
|
void StopRenderThread();
|
||||||
|
@ -65,13 +66,13 @@ private:
|
||||||
class Interpolator
|
class Interpolator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Interpolator() {}
|
constexpr Interpolator() {}
|
||||||
Interpolator(s32 x0, s32 x1, s32 w0, s32 w1)
|
constexpr Interpolator(s32 x0, s32 x1, s32 w0, s32 w1)
|
||||||
{
|
{
|
||||||
Setup(x0, x1, w0, 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->x0 = x0;
|
||||||
this->x1 = x1;
|
this->x1 = x1;
|
||||||
|
@ -123,7 +124,7 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetX(s32 x)
|
constexpr void SetX(s32 x)
|
||||||
{
|
{
|
||||||
x -= x0;
|
x -= x0;
|
||||||
this->x = x;
|
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;
|
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;
|
if (xdiff == 0 || z0 == z1) return z0;
|
||||||
|
|
||||||
|
@ -228,9 +229,9 @@ private:
|
||||||
class Slope
|
class Slope
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Slope() {}
|
constexpr Slope() {}
|
||||||
|
|
||||||
s32 SetupDummy(s32 x0)
|
constexpr s32 SetupDummy(s32 x0)
|
||||||
{
|
{
|
||||||
dx = 0;
|
dx = 0;
|
||||||
|
|
||||||
|
@ -249,7 +250,7 @@ private:
|
||||||
return x0;
|
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->x0 = x0;
|
||||||
this->y = y;
|
this->y = y;
|
||||||
|
@ -293,7 +294,7 @@ private:
|
||||||
|
|
||||||
XMajor = (Increment > 0x40000);
|
XMajor = (Increment > 0x40000);
|
||||||
|
|
||||||
if (side)
|
if constexpr (side)
|
||||||
{
|
{
|
||||||
// right
|
// right
|
||||||
|
|
||||||
|
@ -324,7 +325,7 @@ private:
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 Step()
|
constexpr s32 Step()
|
||||||
{
|
{
|
||||||
dx += Increment;
|
dx += Increment;
|
||||||
y++;
|
y++;
|
||||||
|
@ -334,7 +335,7 @@ private:
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
s32 XVal()
|
constexpr s32 XVal() const
|
||||||
{
|
{
|
||||||
s32 ret;
|
s32 ret;
|
||||||
if (Negative) ret = x0 - (dx >> 18);
|
if (Negative) ret = x0 - (dx >> 18);
|
||||||
|
@ -346,7 +347,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool swapped>
|
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 do length calc for right side when swapped as it's
|
||||||
// only needed for aa calcs, as actual line spans are broken
|
// only needed for aa calcs, as actual line spans are broken
|
||||||
|
@ -372,7 +373,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool swapped>
|
template<bool swapped>
|
||||||
void EdgeParams_YMajor(s32* length, s32* coverage)
|
constexpr void EdgeParams_YMajor(s32* length, s32* coverage) const
|
||||||
{
|
{
|
||||||
*length = 1;
|
*length = 1;
|
||||||
|
|
||||||
|
@ -404,7 +405,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool swapped>
|
template<bool swapped>
|
||||||
void EdgeParams(s32* length, s32* coverage)
|
constexpr void EdgeParams(s32* length, s32* coverage) const
|
||||||
{
|
{
|
||||||
if (XMajor)
|
if (XMajor)
|
||||||
return EdgeParams_XMajor<swapped>(length, coverage);
|
return EdgeParams_XMajor<swapped>(length, coverage);
|
||||||
|
|
|
@ -33,13 +33,13 @@ namespace melonDS
|
||||||
|
|
||||||
using namespace OpenGL;
|
using namespace OpenGL;
|
||||||
|
|
||||||
std::unique_ptr<GLCompositor> GLCompositor::New(melonDS::GPU& gpu) noexcept
|
std::optional<GLCompositor> GLCompositor::New() noexcept
|
||||||
{
|
{
|
||||||
assert(glBindAttribLocation != nullptr);
|
assert(glBindAttribLocation != nullptr);
|
||||||
|
|
||||||
std::array<GLuint, 3> CompShader {};
|
std::array<GLuint, 3> CompShader {};
|
||||||
if (!OpenGL::BuildShaderProgram(kCompositorVS, kCompositorFS_Nearest, &CompShader[0], "CompositorShader"))
|
if (!OpenGL::BuildShaderProgram(kCompositorVS, kCompositorFS_Nearest, &CompShader[0], "CompositorShader"))
|
||||||
return nullptr;
|
return std::nullopt;
|
||||||
|
|
||||||
glBindAttribLocation(CompShader[2], 0, "vPosition");
|
glBindAttribLocation(CompShader[2], 0, "vPosition");
|
||||||
glBindAttribLocation(CompShader[2], 1, "vTexcoord");
|
glBindAttribLocation(CompShader[2], 1, "vTexcoord");
|
||||||
|
@ -48,12 +48,12 @@ std::unique_ptr<GLCompositor> GLCompositor::New(melonDS::GPU& gpu) noexcept
|
||||||
if (!OpenGL::LinkShaderProgram(CompShader.data()))
|
if (!OpenGL::LinkShaderProgram(CompShader.data()))
|
||||||
// OpenGL::LinkShaderProgram already deletes the shader program object
|
// OpenGL::LinkShaderProgram already deletes the shader program object
|
||||||
// if linking the shaders together failed.
|
// 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");
|
CompScaleLoc = glGetUniformLocation(CompShader[2], "u3DScale");
|
||||||
Comp3DXPosLoc = glGetUniformLocation(CompShader[2], "u3DXPos");
|
Comp3DXPosLoc = glGetUniformLocation(CompShader[2], "u3DXPos");
|
||||||
|
@ -92,7 +92,7 @@ GLCompositor::GLCompositor(std::array<GLuint, 3> compShader, melonDS::GPU& gpu)
|
||||||
|
|
||||||
glGenBuffers(1, &CompVertexBufferID);
|
glGenBuffers(1, &CompVertexBufferID);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 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);
|
glGenVertexArrays(1, &CompVertexArrayID);
|
||||||
glBindVertexArray(CompVertexArrayID);
|
glBindVertexArray(CompVertexArrayID);
|
||||||
|
@ -101,7 +101,7 @@ GLCompositor::GLCompositor(std::array<GLuint, 3> compShader, melonDS::GPU& gpu)
|
||||||
glEnableVertexAttribArray(1); // texcoord
|
glEnableVertexAttribArray(1); // texcoord
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(CompVertex), (void*)(offsetof(CompVertex, 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);
|
glGenTextures(1, &CompScreenInputTex);
|
||||||
glActiveTexture(GL_TEXTURE0);
|
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);
|
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);
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8UI, 256*3 + 1, 192*2, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
|
||||||
glGenTextures(2, CompScreenOutputTex);
|
glGenTextures(CompScreenOutputTex.size(), &CompScreenOutputTex[0]);
|
||||||
for (int i = 0; i < 2; i++)
|
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_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 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);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
@ -129,9 +129,9 @@ GLCompositor::~GLCompositor()
|
||||||
{
|
{
|
||||||
assert(glDeleteFramebuffers != nullptr);
|
assert(glDeleteFramebuffers != nullptr);
|
||||||
|
|
||||||
glDeleteFramebuffers(2, CompScreenOutputFB);
|
glDeleteFramebuffers(CompScreenOutputFB.size(), &CompScreenOutputFB[0]);
|
||||||
glDeleteTextures(1, &CompScreenInputTex);
|
glDeleteTextures(1, &CompScreenInputTex);
|
||||||
glDeleteTextures(2, CompScreenOutputTex);
|
glDeleteTextures(CompScreenOutputTex.size(), &CompScreenOutputTex[0]);
|
||||||
|
|
||||||
glDeleteVertexArrays(1, &CompVertexArrayID);
|
glDeleteVertexArrays(1, &CompVertexArrayID);
|
||||||
glDeleteBuffers(1, &CompVertexBufferID);
|
glDeleteBuffers(1, &CompVertexBufferID);
|
||||||
|
@ -139,14 +139,75 @@ GLCompositor::~GLCompositor()
|
||||||
OpenGL::DeleteShaderProgram(CompShader.data());
|
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;
|
Scale = scale;
|
||||||
ScreenW = 256 * scale;
|
ScreenW = 256 * scale;
|
||||||
|
@ -170,13 +231,12 @@ void GLCompositor::SetRenderSettings(const RenderSettings& settings) noexcept
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCompositor::Stop()
|
void GLCompositor::Stop(const GPU& gpu) noexcept
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
int frontbuf = GPU.FrontBuffer;
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, CompScreenOutputFB[frontbuf]);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, CompScreenOutputFB[gpu.FrontBuffer]);
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
}
|
}
|
||||||
|
@ -184,9 +244,9 @@ void GLCompositor::Stop()
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
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_READ_FRAMEBUFFER, 0);
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, CompScreenOutputFB[frontbuf]);
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, CompScreenOutputFB[frontbuf]);
|
||||||
|
|
||||||
|
@ -204,21 +264,21 @@ void GLCompositor::RenderFrame()
|
||||||
glUniform1ui(CompScaleLoc, Scale);
|
glUniform1ui(CompScaleLoc, Scale);
|
||||||
|
|
||||||
// TODO: support setting this midframe, if ever needed
|
// 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);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, CompScreenInputTex);
|
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,
|
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,
|
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);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
reinterpret_cast<GLRenderer*>(GPU.GPU3D.GetCurrentRenderer())->SetupAccelFrame();
|
renderer.SetupAccelFrame();
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, CompVertexBufferID);
|
glBindBuffer(GL_ARRAY_BUFFER, CompVertexBufferID);
|
||||||
glBindVertexArray(CompVertexArrayID);
|
glBindVertexArray(CompVertexArrayID);
|
||||||
|
|
|
@ -21,51 +21,51 @@
|
||||||
#include "OpenGLSupport.h"
|
#include "OpenGLSupport.h"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <optional>
|
||||||
|
|
||||||
namespace melonDS
|
namespace melonDS
|
||||||
{
|
{
|
||||||
class GPU;
|
class GPU;
|
||||||
struct RenderSettings;
|
struct RenderSettings;
|
||||||
|
class GLRenderer;
|
||||||
class GLCompositor
|
class GLCompositor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static std::unique_ptr<GLCompositor> New(melonDS::GPU& gpu) noexcept;
|
static std::optional<GLCompositor> New() noexcept;
|
||||||
GLCompositor(const GLCompositor&) = delete;
|
GLCompositor(const GLCompositor&) = delete;
|
||||||
GLCompositor& operator=(const GLCompositor&) = delete;
|
GLCompositor& operator=(const GLCompositor&) = delete;
|
||||||
|
GLCompositor(GLCompositor&&) noexcept;
|
||||||
|
GLCompositor& operator=(GLCompositor&&) noexcept;
|
||||||
~GLCompositor();
|
~GLCompositor();
|
||||||
|
|
||||||
void Reset();
|
void SetScaleFactor(int scale) noexcept;
|
||||||
|
[[nodiscard]] int GetScaleFactor() const noexcept { return Scale; }
|
||||||
|
|
||||||
void SetRenderSettings(const RenderSettings& settings) noexcept;
|
void Stop(const GPU& gpu) noexcept;
|
||||||
|
void RenderFrame(const GPU& gpu, GLRenderer& renderer) noexcept;
|
||||||
void Stop();
|
|
||||||
void RenderFrame();
|
|
||||||
void BindOutputTexture(int buf);
|
void BindOutputTexture(int buf);
|
||||||
private:
|
private:
|
||||||
GLCompositor(std::array<GLuint, 3> CompShader, melonDS::GPU& gpu) noexcept;
|
GLCompositor(std::array<GLuint, 3> CompShader) noexcept;
|
||||||
melonDS::GPU& GPU;
|
int Scale = 0;
|
||||||
int Scale;
|
int ScreenH = 0, ScreenW = 0;
|
||||||
int ScreenH, ScreenW;
|
|
||||||
|
|
||||||
std::array<GLuint, 3> CompShader;
|
std::array<GLuint, 3> CompShader {};
|
||||||
GLuint CompScaleLoc;
|
GLuint CompScaleLoc = 0;
|
||||||
GLuint Comp3DXPosLoc;
|
GLuint Comp3DXPosLoc = 0;
|
||||||
|
|
||||||
GLuint CompVertexBufferID;
|
GLuint CompVertexBufferID = 0;
|
||||||
GLuint CompVertexArrayID;
|
GLuint CompVertexArrayID = 0;
|
||||||
|
|
||||||
struct CompVertex
|
struct CompVertex
|
||||||
{
|
{
|
||||||
float Position[2];
|
std::array<float, 2> Position {};
|
||||||
float Texcoord[2];
|
std::array<float, 2> Texcoord {};
|
||||||
};
|
};
|
||||||
CompVertex CompVertices[2 * 3*2];
|
std::array<CompVertex, 2*3*2> CompVertices {};
|
||||||
|
|
||||||
GLuint CompScreenInputTex;
|
GLuint CompScreenInputTex = 0;
|
||||||
GLuint CompScreenOutputTex[2];
|
std::array<GLuint, 2> CompScreenOutputTex {};
|
||||||
GLuint CompScreenOutputFB[2];
|
std::array<GLuint, 2> CompScreenOutputFB {};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,6 +93,8 @@
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
#include "DSi.h"
|
#include "DSi.h"
|
||||||
#include "DSi_I2C.h"
|
#include "DSi_I2C.h"
|
||||||
|
#include "GPU3D_Soft.h"
|
||||||
|
#include "GPU3D_OpenGL.h"
|
||||||
|
|
||||||
#include "Savestate.h"
|
#include "Savestate.h"
|
||||||
|
|
||||||
|
@ -163,7 +165,6 @@ EmuThread* emuThread;
|
||||||
int autoScreenSizing = 0;
|
int autoScreenSizing = 0;
|
||||||
|
|
||||||
int videoRenderer;
|
int videoRenderer;
|
||||||
RenderSettings videoSettings;
|
|
||||||
bool videoSettingsDirty;
|
bool videoSettingsDirty;
|
||||||
|
|
||||||
CameraManager* camManager[2];
|
CameraManager* camManager[2];
|
||||||
|
@ -350,9 +351,6 @@ void EmuThread::run()
|
||||||
autoScreenSizing = 0;
|
autoScreenSizing = 0;
|
||||||
|
|
||||||
videoSettingsDirty = false;
|
videoSettingsDirty = false;
|
||||||
videoSettings.Soft_Threaded = Config::Threaded3D != 0;
|
|
||||||
videoSettings.GL_ScaleFactor = Config::GL_ScaleFactor;
|
|
||||||
videoSettings.GL_BetterPolygons = Config::GL_BetterPolygons;
|
|
||||||
|
|
||||||
if (mainWindow->hasOGL)
|
if (mainWindow->hasOGL)
|
||||||
{
|
{
|
||||||
|
@ -364,8 +362,16 @@ void EmuThread::run()
|
||||||
videoRenderer = 0;
|
videoRenderer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
NDS->GPU.InitRenderer(videoRenderer);
|
if (videoRenderer == 0)
|
||||||
NDS->GPU.SetRenderSettings(videoRenderer, videoSettings);
|
{ // 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);
|
NDS->SPU.SetInterpolation(Config::AudioInterp);
|
||||||
|
|
||||||
|
@ -491,11 +497,16 @@ void EmuThread::run()
|
||||||
|
|
||||||
videoSettingsDirty = false;
|
videoSettingsDirty = false;
|
||||||
|
|
||||||
videoSettings.Soft_Threaded = Config::Threaded3D != 0;
|
if (videoRenderer == 0)
|
||||||
videoSettings.GL_ScaleFactor = Config::GL_ScaleFactor;
|
{ // If we're using the software renderer...
|
||||||
videoSettings.GL_BetterPolygons = Config::GL_BetterPolygons;
|
NDS->GPU.SetRenderer3D(std::make_unique<SoftRenderer>(NDS->GPU, Config::Threaded3D != 0));
|
||||||
|
}
|
||||||
NDS->GPU.SetRenderSettings(videoRenderer, videoSettings);
|
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
|
// process input and hotkeys
|
||||||
|
@ -804,10 +815,10 @@ void EmuThread::drawScreenGL()
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
#ifdef OGLRENDERER_ENABLED
|
#ifdef OGLRENDERER_ENABLED
|
||||||
if (NDS->GPU.Renderer != 0)
|
if (NDS->GPU.GetRenderer3D().Accelerated)
|
||||||
{
|
{
|
||||||
// hardware-accelerated render
|
// hardware-accelerated render
|
||||||
NDS->GPU.CurGLCompositor->BindOutputTexture(frontbuf);
|
static_cast<GLRenderer&>(NDS->GPU.GetRenderer3D()).GetCompositor().BindOutputTexture(frontbuf);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
@ -818,9 +829,9 @@ void EmuThread::drawScreenGL()
|
||||||
if (NDS->GPU.Framebuffer[frontbuf][0] && NDS->GPU.Framebuffer[frontbuf][1])
|
if (NDS->GPU.Framebuffer[frontbuf][0] && NDS->GPU.Framebuffer[frontbuf][1])
|
||||||
{
|
{
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 192, GL_RGBA,
|
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,
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(screen[0].scanLine(0), emuThread->NDS->GPU.Framebuffer[frontbuf][0], 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], 256 * 192 * 4);
|
memcpy(screen[1].scanLine(0), emuThread->NDS->GPU.Framebuffer[frontbuf][1].get(), 256 * 192 * 4);
|
||||||
emuThread->FrontBufferLock.unlock();
|
emuThread->FrontBufferLock.unlock();
|
||||||
|
|
||||||
QRect screenrc(0, 0, 256, 192);
|
QRect screenrc(0, 0, 256, 192);
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define TYPES_H
|
#define TYPES_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
namespace melonDS
|
namespace melonDS
|
||||||
{
|
{
|
||||||
|
@ -32,5 +33,7 @@ typedef int16_t s16;
|
||||||
typedef int32_t s32;
|
typedef int32_t s32;
|
||||||
typedef int64_t s64;
|
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
|
#endif // TYPES_H
|
||||||
|
|
Loading…
Reference in New Issue