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
18 changed files with 309 additions and 206 deletions

View File

@ -18,6 +18,7 @@
#include "GPU_OpenGL.h"
#include <assert.h>
#include <cstdio>
#include <cstring>
@ -32,33 +33,36 @@ 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");
return std::unique_ptr<GLCompositor>(new GLCompositor(CompShader));
}
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
#define SETVERTEX(i, x, y, offset) \
@ -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);