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(); ARMJIT_Memory::DeInit();
delete JITCompiler; delete JITCompiler;
JITCompiler = nullptr;
} }
void Reset() void Reset()

View File

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

View File

@ -128,6 +128,10 @@ void DeInit()
delete[] NWRAM_A; delete[] NWRAM_A;
delete[] NWRAM_B; delete[] NWRAM_B;
delete[] NWRAM_C; delete[] NWRAM_C;
NWRAM_A = nullptr;
NWRAM_B = nullptr;
NWRAM_C = nullptr;
#endif #endif
DSi_I2C::DeInit(); DSi_I2C::DeInit();
@ -135,10 +139,16 @@ void DeInit()
DSi_AES::DeInit(); DSi_AES::DeInit();
DSi_DSP::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; delete SDMMC;
SDMMC = nullptr;
delete SDIO; delete SDIO;
SDIO = nullptr;
} }
void Reset() void Reset()

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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