From 6acf7818eafe40a4ecf95f0c4f3139fe26108933 Mon Sep 17 00:00:00 2001 From: rogerman Date: Wed, 16 Aug 2017 22:27:38 -0700 Subject: [PATCH] OpenGL Renderer: Translucent fragments now correctly overwrite zero-alpha destination fragments when running MSAA. (Related to commit 3b354a0.) --- desmume/src/OGLRender.cpp | 287 ++++++++++++++++++---------------- desmume/src/OGLRender.h | 19 ++- desmume/src/OGLRender_3_2.cpp | 196 ++++++++++++++++++++--- 3 files changed, 336 insertions(+), 166 deletions(-) diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index cd97f33d5..d9d2d17a7 100755 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -1062,18 +1062,15 @@ OpenGLRenderer::OpenGLRenderer() isFBOSupported = false; isMultisampledFBOSupported = false; isShaderSupported = false; + isSampleShadingSupported = false; isVAOSupported = false; willFlipOnlyFramebufferOnGPU = false; willFlipAndConvertFramebufferOnGPU = false; + willUsePerSampleZeroDstPass = false; // Init OpenGL rendering states ref = new OGLRenderRef; - ref->fboRenderID = 0; - ref->fboMSIntermediateRenderID = 0; - ref->fboPostprocessID = 0; - ref->selectedRenderingFBO = 0; - ref->texGDepthStencilAlphaID = 0; - ref->texFinalColorID = 0; + memset(ref, 0, sizeof(OGLRenderRef)); _mappedFramebuffer = NULL; _workingTextureUnpackBuffer = (FragmentColor *)malloc_alignedCacheLine(1024 * 1024 * sizeof(FragmentColor)); @@ -1719,6 +1716,7 @@ OpenGLRenderer_1_2::~OpenGLRenderer_1_2() DestroyPostprocessingPrograms(); DestroyGeometryProgram(); + isShaderSupported = false; DestroyVAOs(); DestroyVBOs(); @@ -1781,7 +1779,8 @@ Render3DError OpenGLRenderer_1_2::InitExtensions() if ( (maxDrawBuffersOGL >= 4) && (maxShaderTexUnitsOGL >= 8) ) { error = this->InitGeometryProgram(GeometryVtxShader_100, GeometryFragShader_100, - GeometryZeroDstAlphaPixelMaskVtxShader_100, GeometryZeroDstAlphaPixelMaskFragShader_100); + GeometryZeroDstAlphaPixelMaskVtxShader_100, GeometryZeroDstAlphaPixelMaskFragShader_100, + NULL, NULL); if (error == OGLERROR_NOERR) { error = this->InitPostprocessingPrograms(ZeroAlphaPixelMaskVtxShader_100, @@ -1797,6 +1796,7 @@ Render3DError OpenGLRenderer_1_2::InitExtensions() if (error != OGLERROR_NOERR) { + this->DestroyPostprocessingPrograms(); this->DestroyGeometryProgram(); this->isShaderSupported = false; } @@ -2091,7 +2091,8 @@ Render3DError OpenGLRenderer_1_2::InitGeometryZeroDstAlphaProgramShaderLocations } Render3DError OpenGLRenderer_1_2::InitGeometryProgram(const char *geometryVtxShaderCString, const char *geometryFragShaderCString, - const char *geometryAlphaVtxShaderCString, const char *geometryAlphaFragShaderCString) + const char *geometryAlphaVtxShaderCString, const char *geometryAlphaFragShaderCString, + const char *geometryMSAlphaVtxShaderCString, const char *geometryMSAlphaFragShaderCString) { OGLRenderRef &OGLRef = *this->ref; @@ -2107,7 +2108,6 @@ Render3DError OpenGLRenderer_1_2::InitGeometryProgram(const char *geometryVtxSha glCompileShader(OGLRef.vertexGeometryShaderID); if (!this->ValidateShaderCompile(OGLRef.vertexGeometryShaderID)) { - glDeleteShader(OGLRef.vertexGeometryShaderID); INFO("OpenGL: Failed to compile the vertex shader. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2115,7 +2115,6 @@ Render3DError OpenGLRenderer_1_2::InitGeometryProgram(const char *geometryVtxSha OGLRef.fragmentGeometryShaderID = glCreateShader(GL_FRAGMENT_SHADER); if(!OGLRef.fragmentGeometryShaderID) { - glDeleteShader(OGLRef.vertexGeometryShaderID); INFO("OpenGL: Failed to create the fragment shader. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2125,8 +2124,6 @@ Render3DError OpenGLRenderer_1_2::InitGeometryProgram(const char *geometryVtxSha glCompileShader(OGLRef.fragmentGeometryShaderID); if (!this->ValidateShaderCompile(OGLRef.fragmentGeometryShaderID)) { - glDeleteShader(OGLRef.vertexGeometryShaderID); - glDeleteShader(OGLRef.fragmentGeometryShaderID); INFO("OpenGL: Failed to compile the fragment shader. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2134,8 +2131,6 @@ Render3DError OpenGLRenderer_1_2::InitGeometryProgram(const char *geometryVtxSha OGLRef.programGeometryID = glCreateProgram(); if(!OGLRef.programGeometryID) { - glDeleteShader(OGLRef.vertexGeometryShaderID); - glDeleteShader(OGLRef.fragmentGeometryShaderID); INFO("OpenGL: Failed to create the shader program. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2148,11 +2143,6 @@ Render3DError OpenGLRenderer_1_2::InitGeometryProgram(const char *geometryVtxSha glLinkProgram(OGLRef.programGeometryID); if (!this->ValidateShaderProgramLink(OGLRef.programGeometryID)) { - glDetachShader(OGLRef.programGeometryID, OGLRef.vertexGeometryShaderID); - glDetachShader(OGLRef.programGeometryID, OGLRef.fragmentGeometryShaderID); - glDeleteProgram(OGLRef.programGeometryID); - glDeleteShader(OGLRef.vertexGeometryShaderID); - glDeleteShader(OGLRef.fragmentGeometryShaderID); INFO("OpenGL: Failed to link the shader program. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2175,7 +2165,6 @@ Render3DError OpenGLRenderer_1_2::InitGeometryProgram(const char *geometryVtxSha glCompileShader(OGLRef.vtxShaderGeometryZeroDstAlphaID); if (!this->ValidateShaderCompile(OGLRef.vtxShaderGeometryZeroDstAlphaID)) { - glDeleteShader(OGLRef.vtxShaderGeometryZeroDstAlphaID); INFO("OpenGL: Failed to compile the vertex shader. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2183,7 +2172,6 @@ Render3DError OpenGLRenderer_1_2::InitGeometryProgram(const char *geometryVtxSha OGLRef.fragShaderGeometryZeroDstAlphaID = glCreateShader(GL_FRAGMENT_SHADER); if(!OGLRef.fragShaderGeometryZeroDstAlphaID) { - glDeleteShader(OGLRef.vtxShaderGeometryZeroDstAlphaID); INFO("OpenGL: Failed to create the fragment shader. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2193,8 +2181,6 @@ Render3DError OpenGLRenderer_1_2::InitGeometryProgram(const char *geometryVtxSha glCompileShader(OGLRef.fragShaderGeometryZeroDstAlphaID); if (!this->ValidateShaderCompile(OGLRef.fragShaderGeometryZeroDstAlphaID)) { - glDeleteShader(OGLRef.vtxShaderGeometryZeroDstAlphaID); - glDeleteShader(OGLRef.fragShaderGeometryZeroDstAlphaID); INFO("OpenGL: Failed to compile the fragment shader. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2202,8 +2188,6 @@ Render3DError OpenGLRenderer_1_2::InitGeometryProgram(const char *geometryVtxSha OGLRef.programGeometryZeroDstAlphaID = glCreateProgram(); if(!OGLRef.programGeometryZeroDstAlphaID) { - glDeleteShader(OGLRef.vtxShaderGeometryZeroDstAlphaID); - glDeleteShader(OGLRef.fragShaderGeometryZeroDstAlphaID); INFO("OpenGL: Failed to create the shader program. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2211,21 +2195,80 @@ Render3DError OpenGLRenderer_1_2::InitGeometryProgram(const char *geometryVtxSha glAttachShader(OGLRef.programGeometryZeroDstAlphaID, OGLRef.vtxShaderGeometryZeroDstAlphaID); glAttachShader(OGLRef.programGeometryZeroDstAlphaID, OGLRef.fragShaderGeometryZeroDstAlphaID); + // ------------------------------------------ + + bool useMSGeometryProgram = this->isSampleShadingSupported && (geometryMSAlphaVtxShaderCString != NULL) && (geometryMSAlphaFragShaderCString != NULL); + + if (useMSGeometryProgram) + { + OGLRef.vtxShaderMSGeometryZeroDstAlphaID = glCreateShader(GL_VERTEX_SHADER); + if(!OGLRef.vtxShaderMSGeometryZeroDstAlphaID) + { + INFO("OpenGL: Failed to create the vertex shader. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n"); + return OGLERROR_SHADER_CREATE_ERROR; + } + + const char *vertexMSAlphaShaderProgramChar = geometryMSAlphaVtxShaderCString; + glShaderSource(OGLRef.vtxShaderMSGeometryZeroDstAlphaID, 1, (const GLchar **)&vertexMSAlphaShaderProgramChar, NULL); + glCompileShader(OGLRef.vtxShaderMSGeometryZeroDstAlphaID); + if (!this->ValidateShaderCompile(OGLRef.vtxShaderMSGeometryZeroDstAlphaID)) + { + INFO("OpenGL: Failed to compile the vertex shader. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n"); + return OGLERROR_SHADER_CREATE_ERROR; + } + + OGLRef.fragShaderMSGeometryZeroDstAlphaID = glCreateShader(GL_FRAGMENT_SHADER); + if(!OGLRef.fragShaderMSGeometryZeroDstAlphaID) + { + INFO("OpenGL: Failed to create the fragment shader. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n"); + return OGLERROR_SHADER_CREATE_ERROR; + } + + const char *fragmentMSAlphaShaderProgramChar = geometryMSAlphaFragShaderCString; + glShaderSource(OGLRef.fragShaderMSGeometryZeroDstAlphaID, 1, (const GLchar **)&fragmentMSAlphaShaderProgramChar, NULL); + glCompileShader(OGLRef.fragShaderMSGeometryZeroDstAlphaID); + if (!this->ValidateShaderCompile(OGLRef.fragShaderMSGeometryZeroDstAlphaID)) + { + INFO("OpenGL: Failed to compile the fragment shader. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n"); + return OGLERROR_SHADER_CREATE_ERROR; + } + + OGLRef.programMSGeometryZeroDstAlphaID = glCreateProgram(); + if(!OGLRef.programMSGeometryZeroDstAlphaID) + { + INFO("OpenGL: Failed to create the shader program. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n"); + return OGLERROR_SHADER_CREATE_ERROR; + } + + glAttachShader(OGLRef.programMSGeometryZeroDstAlphaID, OGLRef.vtxShaderMSGeometryZeroDstAlphaID); + glAttachShader(OGLRef.programMSGeometryZeroDstAlphaID, OGLRef.fragShaderMSGeometryZeroDstAlphaID); + } + this->InitGeometryZeroDstAlphaProgramBindings(); glLinkProgram(OGLRef.programGeometryZeroDstAlphaID); if (!this->ValidateShaderProgramLink(OGLRef.programGeometryZeroDstAlphaID)) { - glDetachShader(OGLRef.programGeometryZeroDstAlphaID, OGLRef.vtxShaderGeometryZeroDstAlphaID); - glDetachShader(OGLRef.programGeometryZeroDstAlphaID, OGLRef.fragShaderGeometryZeroDstAlphaID); - glDeleteProgram(OGLRef.programGeometryZeroDstAlphaID); - glDeleteShader(OGLRef.vtxShaderGeometryZeroDstAlphaID); - glDeleteShader(OGLRef.fragShaderGeometryZeroDstAlphaID); INFO("OpenGL: Failed to link the shader program. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n"); return OGLERROR_SHADER_CREATE_ERROR; } glValidateProgram(OGLRef.programGeometryZeroDstAlphaID); + + if (useMSGeometryProgram) + { + glLinkProgram(OGLRef.programMSGeometryZeroDstAlphaID); + if (!this->ValidateShaderProgramLink(OGLRef.programMSGeometryZeroDstAlphaID)) + { + INFO("OpenGL: Failed to link the shader program. Disabling shaders and using fixed-function pipeline. Some emulation features will be disabled.\n"); + return OGLERROR_SHADER_CREATE_ERROR; + } + + glValidateProgram(OGLRef.programMSGeometryZeroDstAlphaID); + + this->willUsePerSampleZeroDstPass = true; + } + this->InitGeometryZeroDstAlphaProgramShaderLocations(); // ------------------------------------------ @@ -2250,19 +2293,26 @@ void OpenGLRenderer_1_2::DestroyGeometryProgram() glDetachShader(OGLRef.programGeometryID, OGLRef.vertexGeometryShaderID); glDetachShader(OGLRef.programGeometryID, OGLRef.fragmentGeometryShaderID); - glDeleteProgram(OGLRef.programGeometryID); - glDeleteShader(OGLRef.vertexGeometryShaderID); - glDeleteShader(OGLRef.fragmentGeometryShaderID); - glDetachShader(OGLRef.programGeometryZeroDstAlphaID, OGLRef.vtxShaderGeometryZeroDstAlphaID); glDetachShader(OGLRef.programGeometryZeroDstAlphaID, OGLRef.fragShaderGeometryZeroDstAlphaID); + + glDeleteProgram(OGLRef.programGeometryID); glDeleteProgram(OGLRef.programGeometryZeroDstAlphaID); + + glDeleteShader(OGLRef.vertexGeometryShaderID); + glDeleteShader(OGLRef.fragmentGeometryShaderID); glDeleteShader(OGLRef.vtxShaderGeometryZeroDstAlphaID); glDeleteShader(OGLRef.fragShaderGeometryZeroDstAlphaID); - this->DestroyToonTable(); + OGLRef.programGeometryID = 0; + OGLRef.programGeometryZeroDstAlphaID = 0; - this->isShaderSupported = false; + OGLRef.vertexGeometryShaderID = 0; + OGLRef.fragmentGeometryShaderID = 0; + OGLRef.vtxShaderGeometryZeroDstAlphaID = 0; + OGLRef.fragShaderGeometryZeroDstAlphaID = 0; + + this->DestroyToonTable(); } Render3DError OpenGLRenderer_1_2::CreateVAOs() @@ -2561,6 +2611,7 @@ Render3DError OpenGLRenderer_1_2::CreateMultisampledFBO(GLsizei numSamples) glGenRenderbuffersEXT(1, &OGLRef.rboMSGPolyID); glGenRenderbuffersEXT(1, &OGLRef.rboMSGFogAttrID); glGenRenderbuffersEXT(1, &OGLRef.rboMSGDepthStencilID); + glGenRenderbuffersEXT(1, &OGLRef.rboMSGDepthStencilAlphaID); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGColorID); glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, numSamples, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight); @@ -2570,10 +2621,11 @@ Render3DError OpenGLRenderer_1_2::CreateMultisampledFBO(GLsizei numSamples) glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, numSamples, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthStencilID); glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, numSamples, GL_DEPTH24_STENCIL8_EXT, this->_framebufferWidth, this->_framebufferHeight); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthStencilAlphaID); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, numSamples, GL_DEPTH24_STENCIL8_EXT, this->_framebufferWidth, this->_framebufferHeight); // Set up multisampled rendering FBO glGenFramebuffersEXT(1, &OGLRef.fboMSIntermediateRenderID); - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboMSIntermediateRenderID); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, OGLRef.rboMSGColorID); glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_RENDERBUFFER_EXT, OGLRef.rboMSGPolyID); @@ -2589,6 +2641,22 @@ Render3DError OpenGLRenderer_1_2::CreateMultisampledFBO(GLsizei numSamples) return OGLERROR_FBO_CREATE_ERROR; } + glGenFramebuffersEXT(1, &OGLRef.fboMSIntermediateRenderAlphaID); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboMSIntermediateRenderAlphaID); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, OGLRef.rboMSGColorID); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_RENDERBUFFER_EXT, OGLRef.rboMSGPolyID); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_RENDERBUFFER_EXT, OGLRef.rboMSGFogAttrID); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthStencilAlphaID); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthStencilAlphaID); + + if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) + { + INFO("OpenGL: Failed to create multisampled FBO!\n"); + this->DestroyMultisampledFBO(); + + return OGLERROR_FBO_CREATE_ERROR; + } + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID); INFO("OpenGL: Successfully created multisampled FBO.\n"); @@ -2606,10 +2674,15 @@ void OpenGLRenderer_1_2::DestroyMultisampledFBO() glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glDeleteFramebuffersEXT(1, &OGLRef.fboMSIntermediateRenderID); + glDeleteFramebuffersEXT(1, &OGLRef.fboMSIntermediateRenderAlphaID); glDeleteRenderbuffersEXT(1, &OGLRef.rboMSGColorID); glDeleteRenderbuffersEXT(1, &OGLRef.rboMSGPolyID); glDeleteRenderbuffersEXT(1, &OGLRef.rboMSGFogAttrID); glDeleteRenderbuffersEXT(1, &OGLRef.rboMSGDepthStencilID); + glDeleteRenderbuffersEXT(1, &OGLRef.rboMSGDepthStencilAlphaID); + + OGLRef.fboMSIntermediateRenderID = 0; + OGLRef.fboMSIntermediateRenderAlphaID = 0; this->isMultisampledFBOSupported = false; } @@ -2698,7 +2771,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp glCompileShader(OGLRef.vertexZeroAlphaPixelMaskShaderID); if (!this->ValidateShaderCompile(OGLRef.vertexZeroAlphaPixelMaskShaderID)) { - glDeleteShader(OGLRef.vertexZeroAlphaPixelMaskShaderID); INFO("OpenGL: Failed to compile the zero-alpha pixel mask vertex shader.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2706,7 +2778,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp OGLRef.fragmentZeroAlphaPixelMaskShaderID = glCreateShader(GL_FRAGMENT_SHADER); if(!OGLRef.fragmentZeroAlphaPixelMaskShaderID) { - glDeleteShader(OGLRef.vertexZeroAlphaPixelMaskShaderID); INFO("OpenGL: Failed to create the zero-alpha pixel mask fragment shader.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2716,8 +2787,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp glCompileShader(OGLRef.fragmentZeroAlphaPixelMaskShaderID); if (!this->ValidateShaderCompile(OGLRef.fragmentZeroAlphaPixelMaskShaderID)) { - glDeleteShader(OGLRef.vertexZeroAlphaPixelMaskShaderID); - glDeleteShader(OGLRef.fragmentZeroAlphaPixelMaskShaderID); INFO("OpenGL: Failed to compile the zero-alpha pixel mask fragment shader.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2725,8 +2794,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp OGLRef.programZeroAlphaPixelMaskID = glCreateProgram(); if(!OGLRef.programZeroAlphaPixelMaskID) { - glDeleteShader(OGLRef.vertexZeroAlphaPixelMaskShaderID); - glDeleteShader(OGLRef.fragmentZeroAlphaPixelMaskShaderID); INFO("OpenGL: Failed to create the zero-alpha pixel mask shader program.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2737,11 +2804,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp error = this->InitZeroAlphaPixelMaskProgramBindings(); if (error != OGLERROR_NOERR) { - glDetachShader(OGLRef.programZeroAlphaPixelMaskID, OGLRef.vertexZeroAlphaPixelMaskShaderID); - glDetachShader(OGLRef.programZeroAlphaPixelMaskID, OGLRef.fragmentZeroAlphaPixelMaskShaderID); - glDeleteProgram(OGLRef.programZeroAlphaPixelMaskID); - glDeleteShader(OGLRef.vertexZeroAlphaPixelMaskShaderID); - glDeleteShader(OGLRef.fragmentZeroAlphaPixelMaskShaderID); INFO("OpenGL: Failed to make the zero-alpha pixel mask shader bindings.\n"); return error; } @@ -2749,11 +2811,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp glLinkProgram(OGLRef.programZeroAlphaPixelMaskID); if (!this->ValidateShaderProgramLink(OGLRef.programZeroAlphaPixelMaskID)) { - glDetachShader(OGLRef.programZeroAlphaPixelMaskID, OGLRef.vertexZeroAlphaPixelMaskShaderID); - glDetachShader(OGLRef.programZeroAlphaPixelMaskID, OGLRef.fragmentZeroAlphaPixelMaskShaderID); - glDeleteProgram(OGLRef.programZeroAlphaPixelMaskID); - glDeleteShader(OGLRef.vertexZeroAlphaPixelMaskShaderID); - glDeleteShader(OGLRef.fragmentZeroAlphaPixelMaskShaderID); INFO("OpenGL: Failed to link the zero-alpha pixel mask shader program.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2775,7 +2832,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp glCompileShader(OGLRef.vertexEdgeMarkShaderID); if (!this->ValidateShaderCompile(OGLRef.vertexEdgeMarkShaderID)) { - glDeleteShader(OGLRef.vertexEdgeMarkShaderID); INFO("OpenGL: Failed to compile the edge mark vertex shader.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2783,7 +2839,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp OGLRef.fragmentEdgeMarkShaderID = glCreateShader(GL_FRAGMENT_SHADER); if(!OGLRef.fragmentEdgeMarkShaderID) { - glDeleteShader(OGLRef.vertexEdgeMarkShaderID); INFO("OpenGL: Failed to create the edge mark fragment shader.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2793,8 +2848,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp glCompileShader(OGLRef.fragmentEdgeMarkShaderID); if (!this->ValidateShaderCompile(OGLRef.fragmentEdgeMarkShaderID)) { - glDeleteShader(OGLRef.vertexEdgeMarkShaderID); - glDeleteShader(OGLRef.fragmentEdgeMarkShaderID); INFO("OpenGL: Failed to compile the edge mark fragment shader.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2802,8 +2855,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp OGLRef.programEdgeMarkID = glCreateProgram(); if(!OGLRef.programEdgeMarkID) { - glDeleteShader(OGLRef.vertexEdgeMarkShaderID); - glDeleteShader(OGLRef.fragmentEdgeMarkShaderID); INFO("OpenGL: Failed to create the edge mark shader program.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2814,11 +2865,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp error = this->InitEdgeMarkProgramBindings(); if (error != OGLERROR_NOERR) { - glDetachShader(OGLRef.programEdgeMarkID, OGLRef.vertexEdgeMarkShaderID); - glDetachShader(OGLRef.programEdgeMarkID, OGLRef.fragmentEdgeMarkShaderID); - glDeleteProgram(OGLRef.programEdgeMarkID); - glDeleteShader(OGLRef.vertexEdgeMarkShaderID); - glDeleteShader(OGLRef.fragmentEdgeMarkShaderID); INFO("OpenGL: Failed to make the edge mark shader bindings.\n"); return error; } @@ -2826,11 +2872,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp glLinkProgram(OGLRef.programEdgeMarkID); if (!this->ValidateShaderProgramLink(OGLRef.programEdgeMarkID)) { - glDetachShader(OGLRef.programEdgeMarkID, OGLRef.vertexEdgeMarkShaderID); - glDetachShader(OGLRef.programEdgeMarkID, OGLRef.fragmentEdgeMarkShaderID); - glDeleteProgram(OGLRef.programEdgeMarkID); - glDeleteShader(OGLRef.vertexEdgeMarkShaderID); - glDeleteShader(OGLRef.fragmentEdgeMarkShaderID); INFO("OpenGL: Failed to link the edge mark shader program.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2852,7 +2893,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp glCompileShader(OGLRef.vertexFogShaderID); if (!this->ValidateShaderCompile(OGLRef.vertexFogShaderID)) { - glDeleteShader(OGLRef.vertexFogShaderID); INFO("OpenGL: Failed to compile the fog vertex shader.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2860,7 +2900,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp OGLRef.fragmentFogShaderID = glCreateShader(GL_FRAGMENT_SHADER); if(!OGLRef.fragmentFogShaderID) { - glDeleteShader(OGLRef.vertexFogShaderID); INFO("OpenGL: Failed to create the fog fragment shader.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2870,8 +2909,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp glCompileShader(OGLRef.fragmentFogShaderID); if (!this->ValidateShaderCompile(OGLRef.fragmentFogShaderID)) { - glDeleteShader(OGLRef.vertexFogShaderID); - glDeleteShader(OGLRef.fragmentFogShaderID); INFO("OpenGL: Failed to compile the fog fragment shader.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2879,8 +2916,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp OGLRef.programFogID = glCreateProgram(); if(!OGLRef.programFogID) { - glDeleteShader(OGLRef.vertexFogShaderID); - glDeleteShader(OGLRef.fragmentFogShaderID); INFO("OpenGL: Failed to create the fog shader program.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2891,11 +2926,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp error = this->InitFogProgramBindings(); if (error != OGLERROR_NOERR) { - glDetachShader(OGLRef.programFogID, OGLRef.vertexFogShaderID); - glDetachShader(OGLRef.programFogID, OGLRef.fragmentFogShaderID); - glDeleteProgram(OGLRef.programFogID); - glDeleteShader(OGLRef.vertexFogShaderID); - glDeleteShader(OGLRef.fragmentFogShaderID); INFO("OpenGL: Failed to make the fog shader bindings.\n"); return error; } @@ -2903,11 +2933,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp glLinkProgram(OGLRef.programFogID); if (!this->ValidateShaderProgramLink(OGLRef.programFogID)) { - glDetachShader(OGLRef.programFogID, OGLRef.vertexFogShaderID); - glDetachShader(OGLRef.programFogID, OGLRef.fragmentFogShaderID); - glDeleteProgram(OGLRef.programFogID); - glDeleteShader(OGLRef.vertexFogShaderID); - glDeleteShader(OGLRef.fragmentFogShaderID); INFO("OpenGL: Failed to link the fog shader program.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2929,7 +2954,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp glCompileShader(OGLRef.vertexFramebufferOutputShaderID); if (!this->ValidateShaderCompile(OGLRef.vertexFramebufferOutputShaderID)) { - glDeleteShader(OGLRef.vertexFramebufferOutputShaderID); INFO("OpenGL: Failed to compile the framebuffer output vertex shader.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2937,7 +2961,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp OGLRef.fragmentFramebufferRGBA6665OutputShaderID = glCreateShader(GL_FRAGMENT_SHADER); if(!OGLRef.fragmentFramebufferRGBA6665OutputShaderID) { - glDeleteShader(OGLRef.vertexFramebufferOutputShaderID); INFO("OpenGL: Failed to create the framebuffer output fragment shader.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2945,8 +2968,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp OGLRef.fragmentFramebufferRGBA8888OutputShaderID = glCreateShader(GL_FRAGMENT_SHADER); if(!OGLRef.fragmentFramebufferRGBA8888OutputShaderID) { - glDeleteShader(OGLRef.vertexFramebufferOutputShaderID); - glDeleteShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID); INFO("OpenGL: Failed to create the framebuffer output fragment shader.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2956,9 +2977,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp glCompileShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID); if (!this->ValidateShaderCompile(OGLRef.fragmentFramebufferRGBA6665OutputShaderID)) { - glDeleteShader(OGLRef.vertexFramebufferOutputShaderID); - glDeleteShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID); - glDeleteShader(OGLRef.fragmentFramebufferRGBA8888OutputShaderID); INFO("OpenGL: Failed to compile the framebuffer output fragment shader.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2968,9 +2986,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp glCompileShader(OGLRef.fragmentFramebufferRGBA8888OutputShaderID); if (!this->ValidateShaderCompile(OGLRef.fragmentFramebufferRGBA8888OutputShaderID)) { - glDeleteShader(OGLRef.vertexFramebufferOutputShaderID); - glDeleteShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID); - glDeleteShader(OGLRef.fragmentFramebufferRGBA8888OutputShaderID); INFO("OpenGL: Failed to compile the framebuffer output fragment shader.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2978,9 +2993,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp OGLRef.programFramebufferRGBA6665OutputID = glCreateProgram(); if(!OGLRef.programFramebufferRGBA6665OutputID) { - glDeleteShader(OGLRef.vertexFramebufferOutputShaderID); - glDeleteShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID); - glDeleteShader(OGLRef.fragmentFramebufferRGBA8888OutputShaderID); INFO("OpenGL: Failed to create the framebuffer output shader program.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -2988,9 +3000,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp OGLRef.programFramebufferRGBA8888OutputID = glCreateProgram(); if(!OGLRef.programFramebufferRGBA8888OutputID) { - glDeleteShader(OGLRef.vertexFramebufferOutputShaderID); - glDeleteShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID); - glDeleteShader(OGLRef.fragmentFramebufferRGBA8888OutputShaderID); INFO("OpenGL: Failed to create the framebuffer output shader program.\n"); return OGLERROR_SHADER_CREATE_ERROR; } @@ -3003,16 +3012,6 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp error = this->InitFramebufferOutputProgramBindings(); if (error != OGLERROR_NOERR) { - glDetachShader(OGLRef.programFramebufferRGBA6665OutputID, OGLRef.vertexFramebufferOutputShaderID); - glDetachShader(OGLRef.programFramebufferRGBA6665OutputID, OGLRef.fragmentFramebufferRGBA6665OutputShaderID); - glDetachShader(OGLRef.programFramebufferRGBA8888OutputID, OGLRef.vertexFramebufferOutputShaderID); - glDetachShader(OGLRef.programFramebufferRGBA8888OutputID, OGLRef.fragmentFramebufferRGBA8888OutputShaderID); - - glDeleteProgram(OGLRef.programFramebufferRGBA6665OutputID); - glDeleteProgram(OGLRef.programFramebufferRGBA8888OutputID); - glDeleteShader(OGLRef.vertexFramebufferOutputShaderID); - glDeleteShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID); - glDeleteShader(OGLRef.fragmentFramebufferRGBA8888OutputShaderID); INFO("OpenGL: Failed to make the framebuffer output shader bindings.\n"); return error; } @@ -3022,22 +3021,13 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *zeroAlp if (!this->ValidateShaderProgramLink(OGLRef.programFramebufferRGBA6665OutputID) || !this->ValidateShaderProgramLink(OGLRef.programFramebufferRGBA8888OutputID)) { - glDetachShader(OGLRef.programFramebufferRGBA6665OutputID, OGLRef.vertexFramebufferOutputShaderID); - glDetachShader(OGLRef.programFramebufferRGBA6665OutputID, OGLRef.fragmentFramebufferRGBA6665OutputShaderID); - glDetachShader(OGLRef.programFramebufferRGBA8888OutputID, OGLRef.vertexFramebufferOutputShaderID); - glDetachShader(OGLRef.programFramebufferRGBA8888OutputID, OGLRef.fragmentFramebufferRGBA8888OutputShaderID); - - glDeleteProgram(OGLRef.programFramebufferRGBA6665OutputID); - glDeleteProgram(OGLRef.programFramebufferRGBA8888OutputID); - glDeleteShader(OGLRef.vertexFramebufferOutputShaderID); - glDeleteShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID); - glDeleteShader(OGLRef.fragmentFramebufferRGBA8888OutputShaderID); INFO("OpenGL: Failed to link the framebuffer output shader program.\n"); return OGLERROR_SHADER_CREATE_ERROR; } glValidateProgram(OGLRef.programFramebufferRGBA6665OutputID); glValidateProgram(OGLRef.programFramebufferRGBA8888OutputID); + this->InitFramebufferOutputShaderLocations(); // ------------------------------------------ @@ -3058,16 +3048,23 @@ Render3DError OpenGLRenderer_1_2::DestroyPostprocessingPrograms() OGLRenderRef &OGLRef = *this->ref; glUseProgram(0); + glDetachShader(OGLRef.programZeroAlphaPixelMaskID, OGLRef.vertexZeroAlphaPixelMaskShaderID); glDetachShader(OGLRef.programZeroAlphaPixelMaskID, OGLRef.fragmentZeroAlphaPixelMaskShaderID); glDetachShader(OGLRef.programEdgeMarkID, OGLRef.vertexEdgeMarkShaderID); glDetachShader(OGLRef.programEdgeMarkID, OGLRef.fragmentEdgeMarkShaderID); glDetachShader(OGLRef.programFogID, OGLRef.vertexFogShaderID); glDetachShader(OGLRef.programFogID, OGLRef.fragmentFogShaderID); + glDetachShader(OGLRef.programFramebufferRGBA6665OutputID, OGLRef.vertexFramebufferOutputShaderID); + glDetachShader(OGLRef.programFramebufferRGBA6665OutputID, OGLRef.fragmentFramebufferRGBA6665OutputShaderID); + glDetachShader(OGLRef.programFramebufferRGBA8888OutputID, OGLRef.vertexFramebufferOutputShaderID); + glDetachShader(OGLRef.programFramebufferRGBA8888OutputID, OGLRef.fragmentFramebufferRGBA8888OutputShaderID); glDeleteProgram(OGLRef.programZeroAlphaPixelMaskID); glDeleteProgram(OGLRef.programEdgeMarkID); glDeleteProgram(OGLRef.programFogID); + glDeleteProgram(OGLRef.programFramebufferRGBA6665OutputID); + glDeleteProgram(OGLRef.programFramebufferRGBA8888OutputID); glDeleteShader(OGLRef.vertexZeroAlphaPixelMaskShaderID); glDeleteShader(OGLRef.fragmentZeroAlphaPixelMaskShaderID); @@ -3075,18 +3072,26 @@ Render3DError OpenGLRenderer_1_2::DestroyPostprocessingPrograms() glDeleteShader(OGLRef.fragmentEdgeMarkShaderID); glDeleteShader(OGLRef.vertexFogShaderID); glDeleteShader(OGLRef.fragmentFogShaderID); - - glDetachShader(OGLRef.programFramebufferRGBA6665OutputID, OGLRef.vertexFramebufferOutputShaderID); - glDetachShader(OGLRef.programFramebufferRGBA6665OutputID, OGLRef.fragmentFramebufferRGBA6665OutputShaderID); - glDetachShader(OGLRef.programFramebufferRGBA8888OutputID, OGLRef.vertexFramebufferOutputShaderID); - glDetachShader(OGLRef.programFramebufferRGBA8888OutputID, OGLRef.fragmentFramebufferRGBA8888OutputShaderID); - - glDeleteProgram(OGLRef.programFramebufferRGBA6665OutputID); - glDeleteProgram(OGLRef.programFramebufferRGBA8888OutputID); glDeleteShader(OGLRef.vertexFramebufferOutputShaderID); glDeleteShader(OGLRef.fragmentFramebufferRGBA6665OutputShaderID); glDeleteShader(OGLRef.fragmentFramebufferRGBA8888OutputShaderID); + OGLRef.programZeroAlphaPixelMaskID = 0; + OGLRef.programEdgeMarkID = 0; + OGLRef.programFogID = 0; + OGLRef.programFramebufferRGBA6665OutputID = 0; + OGLRef.programFramebufferRGBA8888OutputID = 0; + + OGLRef.vertexZeroAlphaPixelMaskShaderID = 0; + OGLRef.fragmentZeroAlphaPixelMaskShaderID = 0; + OGLRef.vertexEdgeMarkShaderID = 0; + OGLRef.fragmentEdgeMarkShaderID = 0; + OGLRef.vertexFogShaderID = 0; + OGLRef.fragmentFogShaderID = 0; + OGLRef.vertexFramebufferOutputShaderID = 0; + OGLRef.fragmentFramebufferRGBA6665OutputShaderID = 0; + OGLRef.fragmentFramebufferRGBA8888OutputShaderID = 0; + return OGLERROR_NOERR; } @@ -3224,6 +3229,7 @@ Render3DError OpenGLRenderer_1_2::CreateToonTable() Render3DError OpenGLRenderer_1_2::DestroyToonTable() { glDeleteTextures(1, &this->ref->texToonTableID); + this->ref->texToonTableID = 0; return OGLERROR_NOERR; } @@ -3370,19 +3376,24 @@ Render3DError OpenGLRenderer_1_2::ZeroDstAlphaPass(const POLYLIST *polyList, con return OGLERROR_FEATURE_UNSUPPORTED; } - // For now, we're not going to support this pass with MSAA, so skip it when running MSAA. - if (this->isMultisampledFBOSupported && (OGLRef.selectedRenderingFBO == OGLRef.fboMSIntermediateRenderID)) - { - return OGLERROR_NOERR; - } - // Pre Pass: Fill in the stencil buffer based on the alpha of the current framebuffer color. // Fully transparent pixels (alpha == 0) -- Set stencil buffer to 0 // All other pixels (alpha != 0) -- Set stencil buffer to 1 this->DisableVertexAttributes(); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboRenderAlphaID); + const bool isRunningMSAA = this->isMultisampledFBOSupported && (OGLRef.selectedRenderingFBO == OGLRef.fboMSIntermediateRenderID); + + if (isRunningMSAA) + { + // Just downsample the color buffer now so that we have some texture data to sample from in the non-multisample shader. + // Not perfectly pixel accurate, but it's better than nothing. + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboRenderAlphaID); + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glBlitFramebufferEXT(0, 0, this->_framebufferWidth, this->_framebufferHeight, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + } + + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, (isRunningMSAA) ? OGLRef.fboMSIntermediateRenderAlphaID : OGLRef.fboRenderAlphaID); glDrawBuffer(GL_NONE); glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); @@ -4557,6 +4568,8 @@ Render3DError OpenGLRenderer_1_2::SetFramebufferSize(size_t w, size_t h) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); } + glActiveTextureARB(GL_TEXTURE0_ARB); + if (this->isMultisampledFBOSupported) { GLsizei maxSamplesOGL = (GLsizei)this->_deviceInfo.maxSamples; @@ -4575,8 +4588,6 @@ Render3DError OpenGLRenderer_1_2::SetFramebufferSize(size_t w, size_t h) glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamplesOGL, GL_DEPTH24_STENCIL8_EXT, w, h); } - glActiveTextureARB(GL_TEXTURE0_ARB); - const size_t newFramebufferColorSizeBytes = w * h * sizeof(FragmentColor); this->_framebufferWidth = w; diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h index ea25f0028..a350094f1 100755 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -436,17 +436,20 @@ struct OGLRenderRef GLuint texGDepthStencilID; GLuint texGDepthStencilAlphaID; GLuint texFinalColorID; + GLuint texMSGColorID; GLuint rboMSGColorID; GLuint rboMSGPolyID; GLuint rboMSGFogAttrID; GLuint rboMSGDepthStencilID; + GLuint rboMSGDepthStencilAlphaID; GLuint fboClearImageID; GLuint fboRenderID; GLuint fboRenderAlphaID; GLuint fboPostprocessID; GLuint fboMSIntermediateRenderID; + GLuint fboMSIntermediateRenderAlphaID; GLuint selectedRenderingFBO; // Shader states @@ -458,6 +461,10 @@ struct OGLRenderRef GLuint fragShaderGeometryZeroDstAlphaID; GLuint programGeometryZeroDstAlphaID; + GLuint vtxShaderMSGeometryZeroDstAlphaID; + GLuint fragShaderMSGeometryZeroDstAlphaID; + GLuint programMSGeometryZeroDstAlphaID; + GLuint vertexZeroAlphaPixelMaskShaderID; GLuint vertexEdgeMarkShaderID; GLuint vertexFogShaderID; @@ -626,9 +633,11 @@ protected: bool isMultisampledFBOSupported; bool isShaderSupported; bool isVAOSupported; + bool isSampleShadingSupported; bool willFlipOnlyFramebufferOnGPU; bool willFlipAndConvertFramebufferOnGPU; - + bool willUsePerSampleZeroDstPass; + FragmentColor *_mappedFramebuffer; FragmentColor *_workingTextureUnpackBuffer; bool _pixelReadNeedsFinish; @@ -650,7 +659,9 @@ protected: virtual void DestroyFBOs() = 0; virtual Render3DError CreateMultisampledFBO(GLsizei numSamples) = 0; virtual void DestroyMultisampledFBO() = 0; - virtual Render3DError InitGeometryProgram(const char *geometryVtxShaderCString, const char *geometryFragShaderCString, const char *geometryAlphaVtxShaderCString, const char *geometryAlphaFragShaderCString) = 0; + virtual Render3DError InitGeometryProgram(const char *geometryVtxShaderCString, const char *geometryFragShaderCString, + const char *geometryAlphaVtxShaderCString, const char *geometryAlphaFragShaderCString, + const char *geometryMSAlphaVtxShaderCString, const char *geometryMSAlphaFragShaderCString) = 0; virtual void DestroyGeometryProgram() = 0; virtual Render3DError CreateVAOs() = 0; virtual void DestroyVAOs() = 0; @@ -725,7 +736,9 @@ protected: virtual Render3DError InitFinalRenderStates(const std::set *oglExtensionSet); virtual Render3DError InitTables(); - virtual Render3DError InitGeometryProgram(const char *geometryVtxShaderCString, const char *geometryFragShaderCString, const char *geometryAlphaVtxShaderCString, const char *geometryAlphaFragShaderCString); + virtual Render3DError InitGeometryProgram(const char *geometryVtxShaderCString, const char *geometryFragShaderCString, + const char *geometryAlphaVtxShaderCString, const char *geometryAlphaFragShaderCString, + const char *geometryMSAlphaVtxShaderCString, const char *geometryMSAlphaFragShaderCString); virtual Render3DError InitGeometryProgramBindings(); virtual Render3DError InitGeometryProgramShaderLocations(); virtual Render3DError InitGeometryZeroDstAlphaProgramBindings(); diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index 719aa865b..70b148f0f 100644 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -304,6 +304,42 @@ static const char *GeometryZeroDstAlphaPixelMaskFragShader_150 = {"\ }\n\ "}; +// Vertex shader for determining which pixels have a zero alpha, GLSL 1.50 +static const char *MSGeometryZeroDstAlphaPixelMaskVtxShader_150 = {"\ + #version 150\n\ + #extension GL_ARB_sample_shading : require\n\ + \n\ + in vec2 inPosition;\n\ + in vec2 inTexCoord0;\n\ + uniform sampler2DMS texInFragColor;\n\ + out vec2 texCoord;\n\ + \n\ + void main()\n\ + {\n\ + texCoord = inTexCoord0 * textureSize(texInFragColor);\n\ + gl_Position = vec4(inPosition, 0.0, 1.0);\n\ + }\n\ +"}; + +// Fragment shader for determining which pixels have a zero alpha, GLSL 1.50 +static const char *MSGeometryZeroDstAlphaPixelMaskFragShader_150 = {"\ + #version 150\n\ + #extension GL_ARB_sample_shading : require\n\ + \n\ + in vec2 texCoord;\n\ + uniform sampler2DMS texInFragColor;\n\ + \n\ + void main()\n\ + {\n\ + vec4 inFragColor = texelFetch(texInFragColor, ivec2(texCoord), gl_SampleID);\n\ + \n\ + if (inFragColor.a <= 0.001)\n\ + {\n\ + discard;\n\ + }\n\ + }\n\ +"}; + // Vertex shader for determining which pixels have a zero alpha, GLSL 1.50 static const char *ZeroAlphaPixelMaskVtxShader_150 = {"\ #version 150\n\ @@ -646,14 +682,21 @@ Render3DError OpenGLRenderer_3_2::InitExtensions() this->willFlipOnlyFramebufferOnGPU = true; this->willFlipAndConvertFramebufferOnGPU = true; + this->isSampleShadingSupported = this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_sample_shading"); + error = this->InitGeometryProgram(GeometryVtxShader_150, GeometryFragShader_150, - GeometryZeroDstAlphaPixelMaskVtxShader_150, GeometryZeroDstAlphaPixelMaskFragShader_150); + GeometryZeroDstAlphaPixelMaskVtxShader_150, GeometryZeroDstAlphaPixelMaskFragShader_150, + MSGeometryZeroDstAlphaPixelMaskVtxShader_150, MSGeometryZeroDstAlphaPixelMaskFragShader_150); if (error != OGLERROR_NOERR) { + this->DestroyGeometryProgram(); this->isShaderSupported = false; + return error; } + this->willUsePerSampleZeroDstPass = this->isSampleShadingSupported && (OGLRef.programMSGeometryZeroDstAlphaID != 0); + error = this->InitPostprocessingPrograms(ZeroAlphaPixelMaskVtxShader_150, ZeroAlphaPixelMaskFragShader_150, EdgeMarkVtxShader_150, @@ -665,8 +708,10 @@ Render3DError OpenGLRenderer_3_2::InitExtensions() FramebufferOutputFragShader_150); if (error != OGLERROR_NOERR) { + this->DestroyPostprocessingPrograms(); this->DestroyGeometryProgram(); this->isShaderSupported = false; + return error; } @@ -1044,25 +1089,50 @@ Render3DError OpenGLRenderer_3_2::CreateMultisampledFBO(GLsizei numSamples) OGLRenderRef &OGLRef = *this->ref; // Set up FBO render targets - glGenRenderbuffers(1, &OGLRef.rboMSGColorID); glGenRenderbuffers(1, &OGLRef.rboMSGPolyID); glGenRenderbuffers(1, &OGLRef.rboMSGFogAttrID); glGenRenderbuffers(1, &OGLRef.rboMSGDepthStencilID); + glGenRenderbuffers(1, &OGLRef.rboMSGDepthStencilAlphaID); + + if (this->willUsePerSampleZeroDstPass) + { + glGenTextures(1, &OGLRef.texMSGColorID); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGColorID); + glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D_MULTISAMPLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, numSamples, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight, GL_TRUE); + } + else + { + glGenRenderbuffers(1, &OGLRef.rboMSGColorID); + glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGColorID); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight); + } - glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGColorID); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight); glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGPolyID); glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight); glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGFogAttrID); glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight); glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilID); glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_DEPTH24_STENCIL8, this->_framebufferWidth, this->_framebufferHeight); + glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilAlphaID); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_DEPTH24_STENCIL8, this->_framebufferWidth, this->_framebufferHeight); // Set up multisampled rendering FBO glGenFramebuffers(1, &OGLRef.fboMSIntermediateRenderID); - glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboMSIntermediateRenderID); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, OGLRef.rboMSGColorID); + + if (this->willUsePerSampleZeroDstPass) + { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGColorID, 0); + } + else + { + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, OGLRef.rboMSGColorID); + } + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, OGLRef.rboMSGPolyID); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_RENDERBUFFER, OGLRef.rboMSGFogAttrID); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilID); @@ -1075,6 +1145,30 @@ Render3DError OpenGLRenderer_3_2::CreateMultisampledFBO(GLsizei numSamples) return OGLERROR_FBO_CREATE_ERROR; } + glGenFramebuffers(1, &OGLRef.fboMSIntermediateRenderAlphaID); + glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboMSIntermediateRenderAlphaID); + + if (this->willUsePerSampleZeroDstPass) + { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGColorID, 0); + } + else + { + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, OGLRef.rboMSGColorID); + } + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, OGLRef.rboMSGPolyID); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_RENDERBUFFER, OGLRef.rboMSGFogAttrID); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilAlphaID); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + INFO("OpenGL: Failed to create multisampled FBO. Multisample antialiasing will be disabled!\n"); + this->DestroyMultisampledFBO(); + + return OGLERROR_FBO_CREATE_ERROR; + } + glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboRenderID); INFO("OpenGL: Successfully created multisampled FBO.\n"); @@ -1092,12 +1186,16 @@ void OpenGLRenderer_3_2::DestroyMultisampledFBO() glBindFramebuffer(GL_FRAMEBUFFER, 0); glDeleteFramebuffers(1, &OGLRef.fboMSIntermediateRenderID); + glDeleteFramebuffers(1, &OGLRef.fboMSIntermediateRenderAlphaID); + glDeleteTextures(1, &OGLRef.texMSGColorID); glDeleteRenderbuffers(1, &OGLRef.rboMSGColorID); glDeleteRenderbuffers(1, &OGLRef.rboMSGPolyID); glDeleteRenderbuffers(1, &OGLRef.rboMSGFogAttrID); glDeleteRenderbuffers(1, &OGLRef.rboMSGDepthStencilID); + glDeleteRenderbuffers(1, &OGLRef.rboMSGDepthStencilAlphaID); OGLRef.fboMSIntermediateRenderID = 0; + OGLRef.fboMSIntermediateRenderAlphaID = 0; this->isMultisampledFBOSupported = false; } @@ -1216,6 +1314,12 @@ Render3DError OpenGLRenderer_3_2::InitGeometryZeroDstAlphaProgramBindings() glBindAttribLocation(OGLRef.programGeometryZeroDstAlphaID, OGLVertexAttributeID_Position, "inPosition"); glBindAttribLocation(OGLRef.programGeometryZeroDstAlphaID, OGLVertexAttributeID_TexCoord0, "inTexCoord0"); + if (OGLRef.programMSGeometryZeroDstAlphaID != 0) + { + glBindAttribLocation(OGLRef.programMSGeometryZeroDstAlphaID, OGLVertexAttributeID_Position, "inPosition"); + glBindAttribLocation(OGLRef.programMSGeometryZeroDstAlphaID, OGLVertexAttributeID_TexCoord0, "inTexCoord0"); + } + return OGLERROR_NOERR; } @@ -1224,9 +1328,16 @@ Render3DError OpenGLRenderer_3_2::InitGeometryZeroDstAlphaProgramShaderLocations OGLRenderRef &OGLRef = *this->ref; glUseProgram(OGLRef.programGeometryZeroDstAlphaID); - const GLint uniformTexGColor = glGetUniformLocation(OGLRef.programGeometryZeroDstAlphaID, "texInFragColor"); + GLint uniformTexGColor = glGetUniformLocation(OGLRef.programGeometryZeroDstAlphaID, "texInFragColor"); glUniform1i(uniformTexGColor, OGLTextureUnitID_GColor); + if (OGLRef.programMSGeometryZeroDstAlphaID != 0) + { + glUseProgram(OGLRef.programMSGeometryZeroDstAlphaID); + uniformTexGColor = glGetUniformLocation(OGLRef.programMSGeometryZeroDstAlphaID, "texInFragColor"); + glUniform1i(uniformTexGColor, 0); + } + return OGLERROR_NOERR; } @@ -1248,19 +1359,37 @@ void OpenGLRenderer_3_2::DestroyGeometryProgram() glDetachShader(OGLRef.programGeometryID, OGLRef.vertexGeometryShaderID); glDetachShader(OGLRef.programGeometryID, OGLRef.fragmentGeometryShaderID); - glDeleteProgram(OGLRef.programGeometryID); - glDeleteShader(OGLRef.vertexGeometryShaderID); - glDeleteShader(OGLRef.fragmentGeometryShaderID); - glDetachShader(OGLRef.programGeometryZeroDstAlphaID, OGLRef.vtxShaderGeometryZeroDstAlphaID); glDetachShader(OGLRef.programGeometryZeroDstAlphaID, OGLRef.fragShaderGeometryZeroDstAlphaID); + glDetachShader(OGLRef.programMSGeometryZeroDstAlphaID, OGLRef.vtxShaderMSGeometryZeroDstAlphaID); + glDetachShader(OGLRef.programMSGeometryZeroDstAlphaID, OGLRef.fragShaderMSGeometryZeroDstAlphaID); + + glDeleteProgram(OGLRef.programGeometryID); glDeleteProgram(OGLRef.programGeometryZeroDstAlphaID); + glDeleteProgram(OGLRef.programMSGeometryZeroDstAlphaID); + + glDeleteShader(OGLRef.vertexGeometryShaderID); + glDeleteShader(OGLRef.fragmentGeometryShaderID); glDeleteShader(OGLRef.vtxShaderGeometryZeroDstAlphaID); glDeleteShader(OGLRef.fragShaderGeometryZeroDstAlphaID); + glDeleteShader(OGLRef.vtxShaderMSGeometryZeroDstAlphaID); + glDeleteShader(OGLRef.fragShaderMSGeometryZeroDstAlphaID); + + OGLRef.uboRenderStatesID = 0; + OGLRef.tboPolyStatesID = 0; + + OGLRef.programGeometryID = 0; + OGLRef.programGeometryZeroDstAlphaID = 0; + OGLRef.programMSGeometryZeroDstAlphaID = 0; + + OGLRef.vertexGeometryShaderID = 0; + OGLRef.fragmentGeometryShaderID = 0; + OGLRef.vtxShaderGeometryZeroDstAlphaID = 0; + OGLRef.fragShaderGeometryZeroDstAlphaID = 0; + OGLRef.vtxShaderMSGeometryZeroDstAlphaID = 0; + OGLRef.fragShaderMSGeometryZeroDstAlphaID = 0; this->DestroyToonTable(); - - this->isShaderSupported = false; } void OpenGLRenderer_3_2::GetExtensionSet(std::set *oglExtensionSet) @@ -1291,24 +1420,30 @@ Render3DError OpenGLRenderer_3_2::ZeroDstAlphaPass(const POLYLIST *polyList, con { OGLRenderRef &OGLRef = *this->ref; - // For now, we're not going to support this pass with MSAA, so skip it when running MSAA. - if (this->isMultisampledFBOSupported && (OGLRef.selectedRenderingFBO == OGLRef.fboMSIntermediateRenderID)) - { - return OGLERROR_NOERR; - } - // Pre Pass: Fill in the stencil buffer based on the alpha of the current framebuffer color. // Fully transparent pixels (alpha == 0) -- Set stencil buffer to 0 // All other pixels (alpha != 0) -- Set stencil buffer to 1 this->DisableVertexAttributes(); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OGLRef.fboRenderAlphaID); + const bool isRunningMSAA = this->isMultisampledFBOSupported && (OGLRef.selectedRenderingFBO == OGLRef.fboMSIntermediateRenderID); + const bool isRunningMSAAWithPerSampleShading = isRunningMSAA && this->willUsePerSampleZeroDstPass; // Doing per-sample shading should be a little more accurate than not doing so. + + if (isRunningMSAA && !isRunningMSAAWithPerSampleShading) + { + // Just downsample the color buffer now so that we have some texture data to sample from in the non-multisample shader. + // Not perfectly pixel accurate, but it's better than nothing. + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OGLRef.fboRenderAlphaID); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + glBlitFramebuffer(0, 0, this->_framebufferWidth, this->_framebufferHeight, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + } + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, (isRunningMSAA) ? OGLRef.fboMSIntermediateRenderAlphaID : OGLRef.fboRenderAlphaID); glDrawBuffer(GL_NONE); glClearBufferfi(GL_DEPTH_STENCIL, 0, 0.0f, 0); glBlitFramebuffer(0, 0, this->_framebufferWidth, this->_framebufferHeight, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_DEPTH_BUFFER_BIT, GL_NEAREST); - glUseProgram(OGLRef.programGeometryZeroDstAlphaID); + glUseProgram((isRunningMSAAWithPerSampleShading) ? OGLRef.programMSGeometryZeroDstAlphaID : OGLRef.programGeometryZeroDstAlphaID); glViewport(0, 0, this->_framebufferWidth, this->_framebufferHeight); glDisable(GL_BLEND); glEnable(GL_STENCIL_TEST); @@ -1924,6 +2059,8 @@ Render3DError OpenGLRenderer_3_2::SetFramebufferSize(size_t w, size_t h) glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glActiveTexture(GL_TEXTURE0); + if (this->isMultisampledFBOSupported) { GLsizei maxSamplesOGL = (GLsizei)this->_deviceInfo.maxSamples; @@ -1932,18 +2069,27 @@ Render3DError OpenGLRenderer_3_2::SetFramebufferSize(size_t w, size_t h) maxSamplesOGL = OGLRENDER_MAX_MULTISAMPLES; } - glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGColorID); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, maxSamplesOGL, GL_RGBA, w, h); + if (this->willUsePerSampleZeroDstPass) + { + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGColorID); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, maxSamplesOGL, GL_RGBA, w, h, GL_TRUE); + } + else + { + glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGColorID); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, maxSamplesOGL, GL_RGBA, w, h); + } + glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGPolyID); glRenderbufferStorageMultisample(GL_RENDERBUFFER, maxSamplesOGL, GL_RGBA, w, h); glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGFogAttrID); glRenderbufferStorageMultisample(GL_RENDERBUFFER, maxSamplesOGL, GL_RGBA, w, h); glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilID); glRenderbufferStorageMultisample(GL_RENDERBUFFER, maxSamplesOGL, GL_DEPTH24_STENCIL8, w, h); + glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilAlphaID); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, maxSamplesOGL, GL_DEPTH24_STENCIL8, w, h); } - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthStencilAlphaID); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);