Make the NDS teardown more robust (#1798)

* Make cleanup a little more robust to mitigate undefined behavior

- Add some null checks before cleaning up the GPU3D renderer
- Make sure that all deleted objects are null
- Move cleanup logic out of an assert call
- Note that deleting a null pointer is a no-op, so there's no need to check for null beforehand
- Use RAII for GLCompositor instead of Init/DeInit methods

* Replace a DeInit call that I missed

* Make ARMJIT_Memory less likely to generate errors

- Set FastMem7/9Start to nullptr at the end
- Only close and unmap the file if it's initialized

* Make Renderer3D manage its resources with RAII

* Don't try to deallocate frontend resources that aren't loaded

* Make ARMJIT_Memory::DeInit more robust on the Switch

* Reset MemoryFile on Windows to INVALID_HANDLE_VALUE, not nullptr

- There is a difference

* Don't explicitly store a Valid state in GLCompositor or the 3D renderers

- Instead, create them with static methods while making the actual constructors private

* Make initialization of OpenGL resources fail if OpenGL isn't loaded

* assert that OpenGL is loaded instead of returning failure
This commit is contained in:
Jesse Talavera-Greenberg 2023-09-15 09:31:05 -04:00 committed by GitHub
parent 1aaf22d181
commit db963aa002
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 309 additions and 206 deletions

View File

@ -330,6 +330,7 @@ void DeInit()
ARMJIT_Memory::DeInit();
delete JITCompiler;
JITCompiler = nullptr;
}
void Reset()

View File

@ -308,7 +308,7 @@ HANDLE MemoryFile;
LPVOID ExceptionHandlerHandle;
#else
u8* MemoryBase;
int MemoryFile;
int MemoryFile = -1;
#endif
bool MapIntoRange(u32 addr, u32 num, u32 offset, u32 size)
@ -811,25 +811,58 @@ void DeInit()
{
#if defined(__SWITCH__)
virtmemLock();
if (FastMem9Reservation)
virtmemRemoveReservation(FastMem9Reservation);
if (FastMem7Reservation)
virtmemRemoveReservation(FastMem7Reservation);
FastMem9Reservation = nullptr;
FastMem7Reservation = nullptr;
virtmemUnlock();
svcUnmapProcessCodeMemory(envGetOwnProcessHandle(), (u64)MemoryBaseCodeMem, (u64)MemoryBase, MemoryTotalSize);
free(MemoryBase);
MemoryBase = nullptr;
#elif defined(_WIN32)
assert(UnmapViewOfFile(MemoryBase));
CloseHandle(MemoryFile);
if (MemoryBase)
{
bool viewUnmapped = UnmapViewOfFile(MemoryBase);
assert(viewUnmapped);
MemoryBase = nullptr;
FastMem9Start = nullptr;
FastMem7Start = nullptr;
}
if (MemoryFile)
{
CloseHandle(MemoryFile);
MemoryFile = INVALID_HANDLE_VALUE;
}
if (ExceptionHandlerHandle)
{
RemoveVectoredExceptionHandler(ExceptionHandlerHandle);
ExceptionHandlerHandle = nullptr;
}
#else
sigaction(SIGSEGV, &OldSaSegv, nullptr);
#ifdef __APPLE__
sigaction(SIGBUS, &OldSaBus, nullptr);
#endif
if (MemoryBase)
{
munmap(MemoryBase, MemoryTotalSize);
MemoryBase = nullptr;
FastMem9Start = nullptr;
FastMem7Start = nullptr;
}
if (MemoryFile >= 0)
{
close(MemoryFile);
MemoryFile = -1;
}
#if defined(__ANDROID__)
if (Libandroid)

View File

@ -128,6 +128,10 @@ void DeInit()
delete[] NWRAM_A;
delete[] NWRAM_B;
delete[] NWRAM_C;
NWRAM_A = nullptr;
NWRAM_B = nullptr;
NWRAM_C = nullptr;
#endif
DSi_I2C::DeInit();
@ -135,10 +139,16 @@ void DeInit()
DSi_AES::DeInit();
DSi_DSP::DeInit();
for (int i = 0; i < 8; i++) delete NDMAs[i];
for (int i = 0; i < 8; i++)
{
delete NDMAs[i];
NDMAs[i] = nullptr;
}
delete SDMMC;
SDMMC = nullptr;
delete SDIO;
SDIO = nullptr;
}
void Reset()

View File

@ -63,6 +63,9 @@ void DeInit()
{
delete Camera0;
delete Camera1;
Camera0 = nullptr;
Camera1 = nullptr;
}
void Reset()

View File

@ -171,6 +171,11 @@ void DeInit()
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;
}
void ResetVRAMCache()
@ -388,20 +393,18 @@ void InitRenderer(int renderer)
#ifdef OGLRENDERER_ENABLED
if (renderer == 1)
{
CurGLCompositor = std::make_unique<GLCompositor>();
// Create opengl rendrerer
if (!CurGLCompositor->Init())
CurGLCompositor = GLCompositor::New();
// Create opengl renderer
if (!CurGLCompositor)
{
// Fallback on software renderer
renderer = 0;
GPU3D::CurrentRenderer = std::make_unique<GPU3D::SoftRenderer>();
GPU3D::CurrentRenderer->Init();
}
GPU3D::CurrentRenderer = std::make_unique<GPU3D::GLRenderer>();
if (!GPU3D::CurrentRenderer->Init())
GPU3D::CurrentRenderer = GPU3D::GLRenderer::New();
if (!GPU3D::CurrentRenderer)
{
// Fallback on software renderer
CurGLCompositor->DeInit();
CurGLCompositor.reset();
renderer = 0;
GPU3D::CurrentRenderer = std::make_unique<GPU3D::SoftRenderer>();
@ -411,7 +414,6 @@ void InitRenderer(int renderer)
#endif
{
GPU3D::CurrentRenderer = std::make_unique<GPU3D::SoftRenderer>();
GPU3D::CurrentRenderer->Init();
}
Renderer = renderer;
@ -419,12 +421,12 @@ void InitRenderer(int renderer)
void DeInitRenderer()
{
GPU3D::CurrentRenderer->DeInit();
// Delete the 3D renderer, if it exists
GPU3D::CurrentRenderer.reset();
#ifdef OGLRENDERER_ENABLED
if (Renderer == 1)
{
CurGLCompositor->DeInit();
}
// Delete the compositor, if one exists
CurGLCompositor.reset();
#endif
}

View File

@ -137,14 +137,11 @@ void Write32(u32 addr, u32 val);
class Renderer3D
{
public:
Renderer3D(bool Accelerated);
virtual ~Renderer3D() {};
virtual ~Renderer3D() = default;
Renderer3D(const Renderer3D&) = delete;
Renderer3D& operator=(const Renderer3D&) = delete;
virtual bool Init() = 0;
virtual void DeInit() = 0;
virtual void Reset() = 0;
// This "Accelerated" flag currently communicates if the framebuffer should
@ -159,6 +156,8 @@ public:
virtual void RenderFrame() = 0;
virtual void RestartFrame() {};
virtual u32* GetLine(int line) = 0;
protected:
Renderer3D(bool Accelerated);
};
extern int Renderer;

View File

@ -18,6 +18,7 @@
#include "GPU3D_OpenGL.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "NDS.h"
@ -96,14 +97,20 @@ void SetupDefaultTexParams(GLuint tex)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
GLRenderer::GLRenderer()
: Renderer3D(true)
GLRenderer::GLRenderer() noexcept : Renderer3D(true)
{
// GLRenderer::New() will be used to actually initialize the renderer;
// The various glDelete* functions silently ignore invalid IDs,
// so we can just let the destructor clean up a half-initialized renderer.
}
bool GLRenderer::Init()
std::unique_ptr<GLRenderer> GLRenderer::New() noexcept
{
GLint uni_id;
assert(glEnable != 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());
glEnable(GL_DEPTH_TEST);
glEnable(GL_STENCIL_TEST);
@ -112,86 +119,93 @@ bool GLRenderer::Init()
glClearDepth(1.0);
if (!OpenGL::BuildShaderProgram(kClearVS, kClearFS, ClearShaderPlain, "ClearShader"))
return false;
if (!OpenGL::BuildShaderProgram(kClearVS, kClearFS, result->ClearShaderPlain, "ClearShader"))
return nullptr;
glBindAttribLocation(ClearShaderPlain[2], 0, "vPosition");
glBindFragDataLocation(ClearShaderPlain[2], 0, "oColor");
glBindFragDataLocation(ClearShaderPlain[2], 1, "oAttr");
glBindAttribLocation(result->ClearShaderPlain[2], 0, "vPosition");
glBindFragDataLocation(result->ClearShaderPlain[2], 0, "oColor");
glBindFragDataLocation(result->ClearShaderPlain[2], 1, "oAttr");
if (!OpenGL::LinkShaderProgram(ClearShaderPlain))
return false;
if (!OpenGL::LinkShaderProgram(result->ClearShaderPlain))
return nullptr;
ClearUniformLoc[0] = glGetUniformLocation(ClearShaderPlain[2], "uColor");
ClearUniformLoc[1] = glGetUniformLocation(ClearShaderPlain[2], "uDepth");
ClearUniformLoc[2] = glGetUniformLocation(ClearShaderPlain[2], "uOpaquePolyID");
ClearUniformLoc[3] = glGetUniformLocation(ClearShaderPlain[2], "uFogFlag");
result->ClearUniformLoc[0] = glGetUniformLocation(result->ClearShaderPlain[2], "uColor");
result->ClearUniformLoc[1] = glGetUniformLocation(result->ClearShaderPlain[2], "uDepth");
result->ClearUniformLoc[2] = glGetUniformLocation(result->ClearShaderPlain[2], "uOpaquePolyID");
result->ClearUniformLoc[3] = glGetUniformLocation(result->ClearShaderPlain[2], "uFogFlag");
memset(RenderShader, 0, sizeof(RenderShader));
memset(result->RenderShader, 0, sizeof(RenderShader));
if (!BuildRenderShader(0,
kRenderVS_Z, kRenderFS_ZO)) return false;
if (!BuildRenderShader(RenderFlag_WBuffer,
kRenderVS_W, kRenderFS_WO)) return false;
if (!BuildRenderShader(RenderFlag_Edge,
kRenderVS_Z, kRenderFS_ZE)) return false;
if (!BuildRenderShader(RenderFlag_Edge | RenderFlag_WBuffer,
kRenderVS_W, kRenderFS_WE)) return false;
if (!BuildRenderShader(RenderFlag_Trans,
kRenderVS_Z, kRenderFS_ZT)) return false;
if (!BuildRenderShader(RenderFlag_Trans | RenderFlag_WBuffer,
kRenderVS_W, kRenderFS_WT)) return false;
if (!BuildRenderShader(RenderFlag_ShadowMask,
kRenderVS_Z, kRenderFS_ZSM)) return false;
if (!BuildRenderShader(RenderFlag_ShadowMask | RenderFlag_WBuffer,
kRenderVS_W, kRenderFS_WSM)) return false;
if (!result->BuildRenderShader(0, kRenderVS_Z, kRenderFS_ZO))
return nullptr;
if (!result->BuildRenderShader(RenderFlag_WBuffer, kRenderVS_W, kRenderFS_WO))
return nullptr;
if (!OpenGL::BuildShaderProgram(kFinalPassVS, kFinalPassEdgeFS, FinalPassEdgeShader, "FinalPassEdgeShader"))
return false;
if (!OpenGL::BuildShaderProgram(kFinalPassVS, kFinalPassFogFS, FinalPassFogShader, "FinalPassFogShader"))
return false;
if (!result->BuildRenderShader(RenderFlag_Edge, kRenderVS_Z, kRenderFS_ZE))
return nullptr;
glBindAttribLocation(FinalPassEdgeShader[2], 0, "vPosition");
glBindFragDataLocation(FinalPassEdgeShader[2], 0, "oColor");
if (!result->BuildRenderShader(RenderFlag_Edge | RenderFlag_WBuffer, kRenderVS_W, kRenderFS_WE))
return nullptr;
if (!OpenGL::LinkShaderProgram(FinalPassEdgeShader))
return false;
if (!result->BuildRenderShader(RenderFlag_Trans, kRenderVS_Z, kRenderFS_ZT))
return nullptr;
uni_id = glGetUniformBlockIndex(FinalPassEdgeShader[2], "uConfig");
glUniformBlockBinding(FinalPassEdgeShader[2], uni_id, 0);
if (!result->BuildRenderShader(RenderFlag_Trans | RenderFlag_WBuffer, kRenderVS_W, kRenderFS_WT))
return nullptr;
glUseProgram(FinalPassEdgeShader[2]);
if (!result->BuildRenderShader(RenderFlag_ShadowMask, kRenderVS_Z, kRenderFS_ZSM))
return nullptr;
uni_id = glGetUniformLocation(FinalPassEdgeShader[2], "DepthBuffer");
if (!result->BuildRenderShader(RenderFlag_ShadowMask | RenderFlag_WBuffer, kRenderVS_W, kRenderFS_WSM))
return nullptr;
if (!OpenGL::BuildShaderProgram(kFinalPassVS, kFinalPassEdgeFS, result->FinalPassEdgeShader, "FinalPassEdgeShader"))
return nullptr;
if (!OpenGL::BuildShaderProgram(kFinalPassVS, kFinalPassFogFS, result->FinalPassFogShader, "FinalPassFogShader"))
return nullptr;
glBindAttribLocation(result->FinalPassEdgeShader[2], 0, "vPosition");
glBindFragDataLocation(result->FinalPassEdgeShader[2], 0, "oColor");
if (!OpenGL::LinkShaderProgram(result->FinalPassEdgeShader))
return nullptr;
GLint uni_id = glGetUniformBlockIndex(result->FinalPassEdgeShader[2], "uConfig");
glUniformBlockBinding(result->FinalPassEdgeShader[2], uni_id, 0);
glUseProgram(result->FinalPassEdgeShader[2]);
uni_id = glGetUniformLocation(result->FinalPassEdgeShader[2], "DepthBuffer");
glUniform1i(uni_id, 0);
uni_id = glGetUniformLocation(FinalPassEdgeShader[2], "AttrBuffer");
uni_id = glGetUniformLocation(result->FinalPassEdgeShader[2], "AttrBuffer");
glUniform1i(uni_id, 1);
glBindAttribLocation(FinalPassFogShader[2], 0, "vPosition");
glBindFragDataLocation(FinalPassFogShader[2], 0, "oColor");
glBindAttribLocation(result->FinalPassFogShader[2], 0, "vPosition");
glBindFragDataLocation(result->FinalPassFogShader[2], 0, "oColor");
if (!OpenGL::LinkShaderProgram(FinalPassFogShader))
return false;
if (!OpenGL::LinkShaderProgram(result->FinalPassFogShader))
return nullptr;
uni_id = glGetUniformBlockIndex(FinalPassFogShader[2], "uConfig");
glUniformBlockBinding(FinalPassFogShader[2], uni_id, 0);
uni_id = glGetUniformBlockIndex(result->FinalPassFogShader[2], "uConfig");
glUniformBlockBinding(result->FinalPassFogShader[2], uni_id, 0);
glUseProgram(FinalPassFogShader[2]);
glUseProgram(result->FinalPassFogShader[2]);
uni_id = glGetUniformLocation(FinalPassFogShader[2], "DepthBuffer");
uni_id = glGetUniformLocation(result->FinalPassFogShader[2], "DepthBuffer");
glUniform1i(uni_id, 0);
uni_id = glGetUniformLocation(FinalPassFogShader[2], "AttrBuffer");
uni_id = glGetUniformLocation(result->FinalPassFogShader[2], "AttrBuffer");
glUniform1i(uni_id, 1);
memset(&ShaderConfig, 0, sizeof(ShaderConfig));
memset(&result->ShaderConfig, 0, sizeof(ShaderConfig));
glGenBuffers(1, &ShaderConfigUBO);
glBindBuffer(GL_UNIFORM_BUFFER, ShaderConfigUBO);
static_assert((sizeof(ShaderConfig) & 15) == 0, "");
glBufferData(GL_UNIFORM_BUFFER, sizeof(ShaderConfig), &ShaderConfig, GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, ShaderConfigUBO);
glGenBuffers(1, &result->ShaderConfigUBO);
glBindBuffer(GL_UNIFORM_BUFFER, result->ShaderConfigUBO);
static_assert((sizeof(ShaderConfig) & 15) == 0);
glBufferData(GL_UNIFORM_BUFFER, sizeof(ShaderConfig), &result->ShaderConfig, GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, result->ShaderConfigUBO);
float clearvtx[6*2] =
@ -205,22 +219,22 @@ bool GLRenderer::Init()
1.0, 1.0
};
glGenBuffers(1, &ClearVertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, ClearVertexBufferID);
glGenBuffers(1, &result->ClearVertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, result->ClearVertexBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(clearvtx), clearvtx, GL_STATIC_DRAW);
glGenVertexArrays(1, &ClearVertexArrayID);
glBindVertexArray(ClearVertexArrayID);
glGenVertexArrays(1, &result->ClearVertexArrayID);
glBindVertexArray(result->ClearVertexArrayID);
glEnableVertexAttribArray(0); // position
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)(0));
glGenBuffers(1, &VertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexBuffer), NULL, GL_DYNAMIC_DRAW);
glGenBuffers(1, &result->VertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, result->VertexBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexBuffer), nullptr, GL_DYNAMIC_DRAW);
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
glGenVertexArrays(1, &result->VertexArrayID);
glBindVertexArray(result->VertexArrayID);
glEnableVertexAttribArray(0); // position
glVertexAttribIPointer(0, 4, GL_UNSIGNED_SHORT, 7*4, (void*)(0));
glEnableVertexAttribArray(1); // color
@ -230,43 +244,43 @@ bool GLRenderer::Init()
glEnableVertexAttribArray(3); // attrib
glVertexAttribIPointer(3, 3, GL_UNSIGNED_INT, 7*4, (void*)(4*4));
glGenBuffers(1, &IndexBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(IndexBuffer), NULL, GL_DYNAMIC_DRAW);
glGenBuffers(1, &result->IndexBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, result->IndexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(IndexBuffer), nullptr, GL_DYNAMIC_DRAW);
glGenFramebuffers(4, &FramebufferID[0]);
glBindFramebuffer(GL_FRAMEBUFFER, FramebufferID[0]);
glGenFramebuffers(4, &result->FramebufferID[0]);
glBindFramebuffer(GL_FRAMEBUFFER, result->FramebufferID[0]);
glGenTextures(8, &FramebufferTex[0]);
FrontBuffer = 0;
glGenTextures(8, &result->FramebufferTex[0]);
result->FrontBuffer = 0;
// color buffers
SetupDefaultTexParams(FramebufferTex[0]);
SetupDefaultTexParams(FramebufferTex[1]);
SetupDefaultTexParams(result->FramebufferTex[0]);
SetupDefaultTexParams(result->FramebufferTex[1]);
// depth/stencil buffer
SetupDefaultTexParams(FramebufferTex[4]);
SetupDefaultTexParams(FramebufferTex[6]);
SetupDefaultTexParams(result->FramebufferTex[4]);
SetupDefaultTexParams(result->FramebufferTex[6]);
// attribute buffer
// R: opaque polyID (for edgemarking)
// G: edge flag
// B: fog flag
SetupDefaultTexParams(FramebufferTex[5]);
SetupDefaultTexParams(FramebufferTex[7]);
SetupDefaultTexParams(result->FramebufferTex[5]);
SetupDefaultTexParams(result->FramebufferTex[7]);
// downscale framebuffer for display capture (always 256x192)
SetupDefaultTexParams(FramebufferTex[3]);
SetupDefaultTexParams(result->FramebufferTex[3]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 192, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glEnable(GL_BLEND);
glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
glGenBuffers(1, &PixelbufferID);
glGenBuffers(1, &result->PixelbufferID);
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &TexMemID);
glBindTexture(GL_TEXTURE_2D, TexMemID);
glGenTextures(1, &result->TexMemID);
glBindTexture(GL_TEXTURE_2D, result->TexMemID);
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);
@ -274,8 +288,8 @@ bool GLRenderer::Init()
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, 1024, 512, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, NULL);
glActiveTexture(GL_TEXTURE1);
glGenTextures(1, &TexPalMemID);
glBindTexture(GL_TEXTURE_2D, TexPalMemID);
glGenTextures(1, &result->TexPalMemID);
glBindTexture(GL_TEXTURE_2D, result->TexPalMemID);
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);
@ -284,11 +298,13 @@ bool GLRenderer::Init()
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return true;
return result;
}
void GLRenderer::DeInit()
GLRenderer::~GLRenderer()
{
assert(glDeleteTextures != nullptr);
glDeleteTextures(1, &TexMemID);
glDeleteTextures(1, &TexPalMemID);

View File

@ -28,10 +28,7 @@ namespace GPU3D
class GLRenderer : public Renderer3D
{
public:
GLRenderer();
virtual ~GLRenderer() override {};
virtual bool Init() override;
virtual void DeInit() override;
virtual ~GLRenderer() override;
virtual void Reset() override;
virtual void SetRenderSettings(GPU::RenderSettings& settings) override;
@ -42,7 +39,11 @@ public:
void SetupAccelFrame();
void PrepareCaptureFrame();
static std::unique_ptr<GLRenderer> New() noexcept;
private:
// Used by New()
GLRenderer() noexcept;
// GL version requirements
// * texelFetch: 3.0 (GLSL 1.30) (3.2/1.50 for MS)
@ -62,7 +63,7 @@ private:
u32 RenderKey;
};
RendererPolygon PolygonList[2048];
RendererPolygon PolygonList[2048] {};
bool BuildRenderShader(u32 flags, const char* vs, const char* fs);
void UseRenderShader(u32 flags);
@ -83,13 +84,13 @@ private:
};
GLuint ClearShaderPlain[3];
GLuint ClearShaderPlain[3] {};
GLuint RenderShader[16][3];
GLuint RenderShader[16][3] {};
GLuint CurShaderID = -1;
GLuint FinalPassEdgeShader[3];
GLuint FinalPassFogShader[3];
GLuint FinalPassEdgeShader[3] {};
GLuint FinalPassFogShader[3] {};
// std140 compliant structure
struct
@ -104,13 +105,13 @@ private:
u32 uFogOffset; // int 304 / 1
u32 uFogShift; // int 305 / 1
u32 _pad1[2]; // int 306 / 2
} ShaderConfig;
} ShaderConfig {};
GLuint ShaderConfigUBO;
int NumFinalPolys, NumOpaqueFinalPolys;
GLuint ShaderConfigUBO {};
int NumFinalPolys {}, NumOpaqueFinalPolys {};
GLuint ClearVertexBufferID, ClearVertexArrayID;
GLint ClearUniformLoc[4];
GLuint ClearVertexBufferID = 0, ClearVertexArrayID {};
GLint ClearUniformLoc[4] {};
// vertex buffer
// * XYZW: 4x16bit
@ -124,28 +125,28 @@ private:
// * bit8: front-facing (?)
// * bit9: W-buffering (?)
GLuint VertexBufferID;
u32 VertexBuffer[10240 * 7];
u32 NumVertices;
GLuint VertexBufferID {};
u32 VertexBuffer[10240 * 7] {};
u32 NumVertices {};
GLuint VertexArrayID;
GLuint IndexBufferID;
u16 IndexBuffer[2048 * 40];
u32 NumIndices, NumEdgeIndices;
GLuint VertexArrayID {};
GLuint IndexBufferID {};
u16 IndexBuffer[2048 * 40] {};
u32 NumIndices {}, NumEdgeIndices {};
const u32 EdgeIndicesOffset = 2048 * 30;
GLuint TexMemID;
GLuint TexPalMemID;
GLuint TexMemID {};
GLuint TexPalMemID {};
int ScaleFactor;
bool BetterPolygons;
int ScreenW, ScreenH;
int ScaleFactor {};
bool BetterPolygons {};
int ScreenW {}, ScreenH {};
GLuint FramebufferTex[8];
int FrontBuffer;
GLuint FramebufferID[4], PixelbufferID;
u32 Framebuffer[256*192];
GLuint FramebufferTex[8] {};
int FrontBuffer {};
GLuint FramebufferID[4] {}, PixelbufferID {};
u32 Framebuffer[256*192] {};
};

View File

@ -71,13 +71,8 @@ void SoftRenderer::SetupRenderThread()
}
SoftRenderer::SoftRenderer()
SoftRenderer::SoftRenderer() noexcept
: Renderer3D(false)
{
}
bool SoftRenderer::Init()
{
Sema_RenderStart = Platform::Semaphore_Create();
Sema_RenderDone = Platform::Semaphore_Create();
@ -86,11 +81,9 @@ bool SoftRenderer::Init()
Threaded = false;
RenderThreadRunning = false;
RenderThreadRendering = false;
return true;
}
void SoftRenderer::DeInit()
SoftRenderer::~SoftRenderer()
{
StopRenderThread();

View File

@ -28,10 +28,8 @@ namespace GPU3D
class SoftRenderer : public Renderer3D
{
public:
SoftRenderer();
virtual ~SoftRenderer() override {};
virtual bool Init() override;
virtual void DeInit() override;
SoftRenderer() noexcept;
virtual ~SoftRenderer() override;
virtual void Reset() override;
virtual void SetRenderSettings(GPU::RenderSettings& settings) override;

View File

@ -18,6 +18,7 @@
#include "GPU_OpenGL.h"
#include <assert.h>
#include <cstdio>
#include <cstring>
@ -32,34 +33,37 @@ namespace GPU
using namespace OpenGL;
bool GLCompositor::Init()
std::unique_ptr<GLCompositor> GLCompositor::New() noexcept
{
if (!OpenGL::BuildShaderProgram(kCompositorVS, kCompositorFS_Nearest, CompShader[0], "CompositorShader"))
//if (!OpenGL::BuildShaderProgram(kCompositorVS, kCompositorFS_Linear, CompShader[0], "CompositorShader"))
//if (!OpenGL::BuildShaderProgram(kCompositorVS_xBRZ, kCompositorFS_xBRZ, CompShader[0], "CompositorShader"))
return false;
assert(glBindAttribLocation != nullptr);
for (int i = 0; i < 1; i++)
{
GLint uni_id;
std::array<GLuint, 3> CompShader {};
if (!OpenGL::BuildShaderProgram(kCompositorVS, kCompositorFS_Nearest, &CompShader[0], "CompositorShader"))
return nullptr;
glBindAttribLocation(CompShader[i][2], 0, "vPosition");
glBindAttribLocation(CompShader[i][2], 1, "vTexcoord");
glBindFragDataLocation(CompShader[i][2], 0, "oColor");
glBindAttribLocation(CompShader[2], 0, "vPosition");
glBindAttribLocation(CompShader[2], 1, "vTexcoord");
glBindFragDataLocation(CompShader[2], 0, "oColor");
if (!OpenGL::LinkShaderProgram(CompShader[i]))
return false;
if (!OpenGL::LinkShaderProgram(CompShader.data()))
// OpenGL::LinkShaderProgram already deletes the shader program object
// if linking the shaders together failed.
return nullptr;
CompScaleLoc[i] = glGetUniformLocation(CompShader[i][2], "u3DScale");
Comp3DXPosLoc[i] = glGetUniformLocation(CompShader[i][2], "u3DXPos");
glUseProgram(CompShader[i][2]);
uni_id = glGetUniformLocation(CompShader[i][2], "ScreenTex");
glUniform1i(uni_id, 0);
uni_id = glGetUniformLocation(CompShader[i][2], "_3DTex");
glUniform1i(uni_id, 1);
return std::unique_ptr<GLCompositor>(new GLCompositor(CompShader));
}
GLCompositor::GLCompositor(std::array<GLuint, 3> compShader) noexcept : CompShader(compShader)
{
CompScaleLoc = glGetUniformLocation(CompShader[2], "u3DScale");
Comp3DXPosLoc = glGetUniformLocation(CompShader[2], "u3DXPos");
glUseProgram(CompShader[2]);
GLuint screenTextureUniform = glGetUniformLocation(CompShader[2], "ScreenTex");
glUniform1i(screenTextureUniform, 0);
GLuint _3dTextureUniform = glGetUniformLocation(CompShader[2], "_3DTex");
glUniform1i(_3dTextureUniform, 1);
// all this mess is to prevent bleeding
#define SETVERTEX(i, x, y, offset) \
CompVertices[i].Position[0] = x; \
@ -119,12 +123,12 @@ bool GLCompositor::Init()
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return true;
}
void GLCompositor::DeInit()
GLCompositor::~GLCompositor()
{
assert(glDeleteFramebuffers != nullptr);
glDeleteFramebuffers(2, CompScreenOutputFB);
glDeleteTextures(1, &CompScreenInputTex);
glDeleteTextures(2, CompScreenOutputTex);
@ -132,8 +136,7 @@ void GLCompositor::DeInit()
glDeleteVertexArrays(1, &CompVertexArrayID);
glDeleteBuffers(1, &CompVertexBufferID);
for (int i = 0; i < 1; i++)
OpenGL::DeleteShaderProgram(CompShader[i]);
OpenGL::DeleteShaderProgram(CompShader.data());
}
void GLCompositor::Reset()
@ -197,11 +200,11 @@ void GLCompositor::RenderFrame()
glClear(GL_COLOR_BUFFER_BIT);
// TODO: select more shaders (filtering, etc)
OpenGL::UseShaderProgram(CompShader[0]);
glUniform1ui(CompScaleLoc[0], Scale);
OpenGL::UseShaderProgram(CompShader.data());
glUniform1ui(CompScaleLoc, Scale);
// TODO: support setting this midframe, if ever needed
glUniform1i(Comp3DXPosLoc[0], ((int)GPU3D::RenderXPos << 23) >> 23);
glUniform1i(Comp3DXPosLoc, ((int)GPU3D::RenderXPos << 23) >> 23);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, CompScreenInputTex);

View File

@ -20,6 +20,9 @@
#include "OpenGLSupport.h"
#include <array>
#include <memory>
namespace GPU
{
@ -28,12 +31,11 @@ struct RenderSettings;
class GLCompositor
{
public:
GLCompositor() = default;
static std::unique_ptr<GLCompositor> New() noexcept;
GLCompositor(const GLCompositor&) = delete;
GLCompositor& operator=(const GLCompositor&) = delete;
~GLCompositor();
bool Init();
void DeInit();
void Reset();
void SetRenderSettings(RenderSettings& settings);
@ -42,13 +44,14 @@ public:
void RenderFrame();
void BindOutputTexture(int buf);
private:
GLCompositor(std::array<GLuint, 3> CompShader) noexcept;
int Scale;
int ScreenH, ScreenW;
GLuint CompShader[1][3];
GLuint CompScaleLoc[1];
GLuint Comp3DXPosLoc[1];
std::array<GLuint, 3> CompShader;
GLuint CompScaleLoc;
GLuint Comp3DXPosLoc;
GLuint CompVertexBufferID;
GLuint CompVertexArrayID;

View File

@ -226,10 +226,16 @@ void DeInit()
#endif
delete ARM9;
ARM9 = nullptr;
delete ARM7;
ARM7 = nullptr;
for (int i = 0; i < 8; i++)
{
delete DMAs[i];
DMAs[i] = nullptr;
}
NDSCart::DeInit();
GBACart::DeInit();

View File

@ -29,6 +29,12 @@ bool BuildShaderProgram(const char* vs, const char* fs, GLuint* ids, const char*
int len;
int res;
if (!glCreateShader)
{
Log(LogLevel::Error, "OpenGL: Cannot build shader program, OpenGL hasn't been loaded\n");
return false;
}
ids[0] = glCreateShader(GL_VERTEX_SHADER);
len = strlen(vs);
glShaderSource(ids[0], 1, &vs, &len);
@ -87,6 +93,12 @@ bool LinkShaderProgram(GLuint* ids)
{
int res;
if (!glLinkProgram)
{
Log(LogLevel::Error, "OpenGL: Cannot link shader program, OpenGL hasn't been loaded\n");
return false;
}
glLinkProgram(ids[2]);
glDetachShader(ids[2], ids[0]);
@ -115,12 +127,18 @@ bool LinkShaderProgram(GLuint* ids)
void DeleteShaderProgram(GLuint* ids)
{
if (glDeleteProgram)
{ // If OpenGL isn't loaded, then there's no shader program to delete
glDeleteProgram(ids[2]);
}
}
void UseShaderProgram(GLuint* ids)
{
if (glUseProgram)
{ // If OpenGL isn't loaded, then there's no shader program to use
glUseProgram(ids[2]);
}
}
}

View File

@ -91,6 +91,7 @@ bool Init()
void DeInit()
{
if (Firmware) delete[] Firmware;
Firmware = nullptr;
}
u32 FixFirmwareLength(u32 originalLength)

View File

@ -135,12 +135,18 @@ bool Init()
void DeInit()
{
for (int i = 0; i < 16; i++)
{
delete Channels[i];
Channels[i] = nullptr;
}
delete Capture[0];
delete Capture[1];
Capture[0] = nullptr;
Capture[1] = nullptr;
Platform::Mutex_Free(AudioLock);
AudioLock = nullptr;
}
void Reset()

View File

@ -334,12 +334,17 @@ void Init()
void DeInit()
{
if (audioDevice) SDL_CloseAudioDevice(audioDevice);
audioDevice = 0;
MicClose();
SDL_DestroyCond(audioSync);
SDL_DestroyMutex(audioSyncLock);
if (audioSync) SDL_DestroyCond(audioSync);
audioSync = nullptr;
if (audioSyncLock) SDL_DestroyMutex(audioSyncLock);
audioSyncLock = nullptr;
if (micWavBuffer) delete[] micWavBuffer;
micWavBuffer = nullptr;
}
void AudioSync()

View File

@ -296,6 +296,8 @@ bool Init()
}
void DeInit()
{
if (MPQueue)
{
MPQueue->lock();
MPQueueHeader* header = (MPQueueHeader*)MPQueue->data();
@ -307,6 +309,9 @@ void DeInit()
SemPoolDeinit();
MPQueue->detach();
}
MPQueue = nullptr;
delete MPQueue;
}