diff options
Diffstat (limited to 'src/GPU3D_OpenGL.cpp')
-rw-r--r-- | src/GPU3D_OpenGL.cpp | 204 |
1 files changed, 110 insertions, 94 deletions
diff --git a/src/GPU3D_OpenGL.cpp b/src/GPU3D_OpenGL.cpp index ebabd51..9648be3 100644 --- a/src/GPU3D_OpenGL.cpp +++ b/src/GPU3D_OpenGL.cpp @@ -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"); - - memset(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 (!OpenGL::BuildShaderProgram(kFinalPassVS, kFinalPassEdgeFS, FinalPassEdgeShader, "FinalPassEdgeShader")) - return false; - if (!OpenGL::BuildShaderProgram(kFinalPassVS, kFinalPassFogFS, FinalPassFogShader, "FinalPassFogShader")) - return false; + 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"); - glBindAttribLocation(FinalPassEdgeShader[2], 0, "vPosition"); - glBindFragDataLocation(FinalPassEdgeShader[2], 0, "oColor"); + memset(result->RenderShader, 0, sizeof(RenderShader)); - if (!OpenGL::LinkShaderProgram(FinalPassEdgeShader)) - return false; + if (!result->BuildRenderShader(0, kRenderVS_Z, kRenderFS_ZO)) + return nullptr; + + if (!result->BuildRenderShader(RenderFlag_WBuffer, kRenderVS_W, kRenderFS_WO)) + return nullptr; + + if (!result->BuildRenderShader(RenderFlag_Edge, kRenderVS_Z, kRenderFS_ZE)) + return nullptr; + + if (!result->BuildRenderShader(RenderFlag_Edge | RenderFlag_WBuffer, kRenderVS_W, kRenderFS_WE)) + return nullptr; + + if (!result->BuildRenderShader(RenderFlag_Trans, kRenderVS_Z, kRenderFS_ZT)) + return nullptr; + + if (!result->BuildRenderShader(RenderFlag_Trans | RenderFlag_WBuffer, kRenderVS_W, kRenderFS_WT)) + return nullptr; + + if (!result->BuildRenderShader(RenderFlag_ShadowMask, kRenderVS_Z, kRenderFS_ZSM)) + return nullptr; + + if (!result->BuildRenderShader(RenderFlag_ShadowMask | RenderFlag_WBuffer, kRenderVS_W, kRenderFS_WSM)) + return nullptr; - uni_id = glGetUniformBlockIndex(FinalPassEdgeShader[2], "uConfig"); - glUniformBlockBinding(FinalPassEdgeShader[2], uni_id, 0); + if (!OpenGL::BuildShaderProgram(kFinalPassVS, kFinalPassEdgeFS, result->FinalPassEdgeShader, "FinalPassEdgeShader")) + return nullptr; - glUseProgram(FinalPassEdgeShader[2]); + if (!OpenGL::BuildShaderProgram(kFinalPassVS, kFinalPassFogFS, result->FinalPassFogShader, "FinalPassFogShader")) + return nullptr; - uni_id = glGetUniformLocation(FinalPassEdgeShader[2], "DepthBuffer"); + 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); |