From 3ef927100bc140300f55727eed6c8a6b95a52e18 Mon Sep 17 00:00:00 2001 From: rogerman Date: Sat, 20 Jul 2024 20:49:44 -0700 Subject: [PATCH] OpenGL Renderer: Fix some longstanding graphical glitches related to running Edge Mark and Fog with MSAA. - These graphical glitches are resolved only when running 3.2 Core Profile with the GL_ARB_sample_shading extension, available on all modern GPUs. - Do some minor optimizations to the Edge Mark and Fog shaders. - Also fix an FBO attachment bug in legacy OpenGL that was introduced in commit 8b5ac56. --- desmume/src/OGLRender.cpp | 179 ++++++------ desmume/src/OGLRender.h | 21 +- desmume/src/OGLRender_3_2.cpp | 502 +++++++++++++++++++++++++--------- desmume/src/OGLRender_3_2.h | 6 +- desmume/src/OGLRender_ES3.cpp | 4 +- desmume/src/OGLRender_ES3.h | 4 +- 6 files changed, 486 insertions(+), 230 deletions(-) diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 014ae426c..4ec820319 100644 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -553,9 +553,6 @@ void main()\n\ edgeColor[3] = texture1D(texEdgeColor, polyIDInfo[3].r);\n\ edgeColor[4] = texture1D(texEdgeColor, polyIDInfo[4].r);\n\ \n\ - bool isWireframe[5];\n\ - isWireframe[0] = bool(polyIDInfo[0].g);\n\ - \n\ float depth[5];\n\ depth[0] = texture2D(texInFragDepth, texCoord[0]).r;\n\ depth[1] = texture2D(texInFragDepth, texCoord[1]).r;\n\ @@ -563,6 +560,9 @@ void main()\n\ depth[3] = texture2D(texInFragDepth, texCoord[3]).r;\n\ depth[4] = texture2D(texInFragDepth, texCoord[4]).r;\n\ \n\ + bool isWireframe[5];\n\ + isWireframe[0] = bool(polyIDInfo[0].g);\n\ + \n\ vec4 newEdgeColor = vec4(0.0, 0.0, 0.0, 0.0);\n\ \n\ if (!isWireframe[0])\n\ @@ -583,47 +583,19 @@ void main()\n\ \n\ if ( ((gl_FragCoord.x >= FRAMEBUFFER_SIZE_X-1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[1]) && (depth[0] >= depth[1]) && !isWireframe[1])) )\n\ {\n\ - if (gl_FragCoord.x >= FRAMEBUFFER_SIZE_X-1.0)\n\ - {\n\ - newEdgeColor = edgeColor[0];\n\ - }\n\ - else\n\ - {\n\ - newEdgeColor = edgeColor[1];\n\ - }\n\ + newEdgeColor = (gl_FragCoord.x >= FRAMEBUFFER_SIZE_X-1.0) ? edgeColor[0] : edgeColor[1];\n\ }\n\ else if ( ((gl_FragCoord.y >= FRAMEBUFFER_SIZE_Y-1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[2]) && (depth[0] >= depth[2]) && !isWireframe[2])) )\n\ {\n\ - if (gl_FragCoord.y >= FRAMEBUFFER_SIZE_Y-1.0)\n\ - {\n\ - newEdgeColor = edgeColor[0];\n\ - }\n\ - else\n\ - {\n\ - newEdgeColor = edgeColor[2];\n\ - }\n\ + newEdgeColor = (gl_FragCoord.y >= FRAMEBUFFER_SIZE_Y-1.0) ? edgeColor[0] : edgeColor[2];\n\ }\n\ else if ( ((gl_FragCoord.x < 1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[3]) && (depth[0] >= depth[3]) && !isWireframe[3])) )\n\ {\n\ - if (gl_FragCoord.x < 1.0)\n\ - {\n\ - newEdgeColor = edgeColor[0];\n\ - }\n\ - else\n\ - {\n\ - newEdgeColor = edgeColor[3];\n\ - }\n\ + newEdgeColor = (gl_FragCoord.x < 1.0) ? edgeColor[0] : edgeColor[3];\n\ }\n\ else if ( ((gl_FragCoord.y < 1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[4]) && (depth[0] >= depth[4]) && !isWireframe[4])) )\n\ {\n\ - if (gl_FragCoord.y < 1.0)\n\ - {\n\ - newEdgeColor = edgeColor[0];\n\ - }\n\ - else\n\ - {\n\ - newEdgeColor = edgeColor[4];\n\ - }\n\ + newEdgeColor = (gl_FragCoord.y < 1.0) ? edgeColor[0] : edgeColor[4];\n\ }\n\ }\n\ \n\ @@ -658,24 +630,10 @@ void main()\n\ float inFragDepth = texture2D(texInFragDepth, texCoord).r;\n\ vec4 inFogAttributes = texture2D(texInFogAttributes, texCoord);\n\ bool polyEnableFog = (inFogAttributes.r > 0.999);\n\ - vec4 outFogWeight = vec4(0.0);\n\ + float densitySelect = (FOG_STEP == 0) ? ((inFragDepth <= FOG_OFFSETF) ? 0.0 : 1.0) : (inFragDepth * (1024.0/float(FOG_STEP))) + (((-float(FOG_OFFSET)/float(FOG_STEP)) - 0.5) / 32.0);\n\ + float fogMixWeight = texture1D(texFogDensityTable, densitySelect).r;\n\ \n\ - float fogMixWeight = 0.0;\n\ - if (FOG_STEP == 0)\n\ - {\n\ - fogMixWeight = texture1D( texFogDensityTable, (inFragDepth <= FOG_OFFSETF) ? 0.0 : 1.0 ).r;\n\ - }\n\ - else\n\ - {\n\ - fogMixWeight = texture1D( texFogDensityTable, (inFragDepth * (1024.0/float(FOG_STEP))) + (((-float(FOG_OFFSET)/float(FOG_STEP)) - 0.5) / 32.0) ).r;\n\ - }\n\ - \n\ - if (polyEnableFog)\n\ - {\n\ - outFogWeight = (stateEnableFogAlphaOnly) ? vec4(vec3(0.0), fogMixWeight) : vec4(fogMixWeight);\n\ - }\n\ - \n\ - gl_FragColor = outFogWeight;\n\ + gl_FragColor = (polyEnableFog) ? ((stateEnableFogAlphaOnly) ? vec4(vec3(0.0), fogMixWeight) : vec4(fogMixWeight)) : vec4(0.0);\n\ }\n\ "}; @@ -1300,10 +1258,11 @@ OpenGLRenderer::OpenGLRenderer() _isFBOBlitSupported = false; isMultisampledFBOSupported = false; isShaderSupported = false; + _isSampleShadingSupported = false; isVAOSupported = false; _isDepthLEqualPolygonFacingSupported = false; willFlipAndConvertFramebufferOnGPU = false; - willUsePerSampleZeroDstPass = false; + _willUseMultisampleShaders = false; _emulateShadowPolygon = true; _emulateSpecialZeroAlphaBlending = true; @@ -2253,7 +2212,16 @@ Render3DError OpenGLRenderer::ApplyRenderingSettings(const GFX3D_State &renderSt this->_emulateDepthLEqualPolygonFacing = CommonSettings.OpenGL_Emulation_DepthLEqualPolygonFacing && this->_isDepthLEqualPolygonFacingSupported; this->_selectedMultisampleSize = CommonSettings.GFX3D_Renderer_MultisampleSize; + + const bool oldMultisampleShadingFlag = this->_willUseMultisampleShaders; this->_enableMultisampledRendering = ((this->_selectedMultisampleSize >= 2) && this->isMultisampledFBOSupported); + this->_willUseMultisampleShaders = this->_isSampleShadingSupported && this->_enableMultisampledRendering; + if (this->_willUseMultisampleShaders != oldMultisampleShadingFlag) + { + // Fog program IDs don't have their own multisampled versions of the IDs, and so we + // need to reset all of the existing IDs so that the fog programs can be regenerated + this->DestroyFogPrograms(); + } error = Render3D::ApplyRenderingSettings(renderState); if (error != RENDER3DERROR_NOERR) @@ -2842,8 +2810,8 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboColorOutMainID); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, OGLRef.texGColorID, 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, OGLRef.texFinalColorID, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, OGLRef.texCIDepthStencilID, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, OGLRef.texCIDepthStencilID, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, OGLRef.texGDepthStencilID, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, OGLRef.texGDepthStencilID, 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE) { @@ -3341,7 +3309,7 @@ void OpenGLRenderer_1_2::DestroyGeometryZeroDstAlphaProgram() OGLRef.fragShaderGeometryZeroDstAlphaID = 0; } -Render3DError OpenGLRenderer_1_2::CreateEdgeMarkProgram(const char *vtxShaderCString, const char *fragShaderCString) +Render3DError OpenGLRenderer_1_2::CreateEdgeMarkProgram(const bool isMultisample, const char *vtxShaderCString, const char *fragShaderCString) { Render3DError error = OGLERROR_NOERR; OGLRenderRef &OGLRef = *this->ref; @@ -3360,10 +3328,10 @@ Render3DError OpenGLRenderer_1_2::CreateEdgeMarkProgram(const char *vtxShaderCSt std::string fragShaderCode = shaderHeader.str() + std::string(fragShaderCString); error = this->ShaderProgramCreate(OGLRef.vertexEdgeMarkShaderID, - OGLRef.fragmentEdgeMarkShaderID, - OGLRef.programEdgeMarkID, - vtxShaderCode.c_str(), - fragShaderCode.c_str()); + OGLRef.fragmentEdgeMarkShaderID, + OGLRef.programEdgeMarkID, + vtxShaderCode.c_str(), + fragShaderCode.c_str()); if (error != OGLERROR_NOERR) { INFO("OpenGL: Failed to create the EDGE MARK shader program.\n"); @@ -3387,15 +3355,15 @@ Render3DError OpenGLRenderer_1_2::CreateEdgeMarkProgram(const char *vtxShaderCSt glValidateProgram(OGLRef.programEdgeMarkID); glUseProgram(OGLRef.programEdgeMarkID); - const GLint uniformTexGDepth = glGetUniformLocation(OGLRef.programEdgeMarkID, "texInFragDepth"); - const GLint uniformTexGPolyID = glGetUniformLocation(OGLRef.programEdgeMarkID, "texInPolyID"); - const GLint uniformTexEdgeColorTable = glGetUniformLocation(OGLRef.programEdgeMarkID, "texEdgeColor"); + const GLint uniformTexGDepth = glGetUniformLocation(OGLRef.programEdgeMarkID, "texInFragDepth"); + const GLint uniformTexGPolyID = glGetUniformLocation(OGLRef.programEdgeMarkID, "texInPolyID"); + const GLint uniformTexEdgeColorTable = glGetUniformLocation(OGLRef.programEdgeMarkID, "texEdgeColor"); glUniform1i(uniformTexGDepth, OGLTextureUnitID_DepthStencil); glUniform1i(uniformTexGPolyID, OGLTextureUnitID_GPolyID); glUniform1i(uniformTexEdgeColorTable, OGLTextureUnitID_LookupTable); - OGLRef.uniformStateClearPolyID = glGetUniformLocation(OGLRef.programEdgeMarkID, "clearPolyID"); - OGLRef.uniformStateClearDepth = glGetUniformLocation(OGLRef.programEdgeMarkID, "clearDepth"); + OGLRef.uniformStateClearPolyID = glGetUniformLocation(OGLRef.programEdgeMarkID, "clearPolyID"); + OGLRef.uniformStateClearDepth = glGetUniformLocation(OGLRef.programEdgeMarkID, "clearDepth"); return OGLERROR_NOERR; } @@ -3404,23 +3372,39 @@ void OpenGLRenderer_1_2::DestroyEdgeMarkProgram() { OGLRenderRef &OGLRef = *this->ref; - if (!this->isShaderSupported || (OGLRef.programEdgeMarkID == 0)) + if (!this->isShaderSupported) { return; } - glDetachShader(OGLRef.programEdgeMarkID, OGLRef.vertexEdgeMarkShaderID); - glDetachShader(OGLRef.programEdgeMarkID, OGLRef.fragmentEdgeMarkShaderID); - glDeleteProgram(OGLRef.programEdgeMarkID); - glDeleteShader(OGLRef.vertexEdgeMarkShaderID); - glDeleteShader(OGLRef.fragmentEdgeMarkShaderID); + if (OGLRef.programEdgeMarkID != 0) + { + glDetachShader(OGLRef.programEdgeMarkID, OGLRef.vertexEdgeMarkShaderID); + glDetachShader(OGLRef.programEdgeMarkID, OGLRef.fragmentEdgeMarkShaderID); + glDeleteProgram(OGLRef.programEdgeMarkID); + glDeleteShader(OGLRef.vertexEdgeMarkShaderID); + glDeleteShader(OGLRef.fragmentEdgeMarkShaderID); + + OGLRef.programEdgeMarkID = 0; + OGLRef.vertexEdgeMarkShaderID = 0; + OGLRef.fragmentEdgeMarkShaderID = 0; + } - OGLRef.programEdgeMarkID = 0; - OGLRef.vertexEdgeMarkShaderID = 0; - OGLRef.fragmentEdgeMarkShaderID = 0; + if (OGLRef.programMSEdgeMarkID != 0) + { + glDetachShader(OGLRef.programMSEdgeMarkID, OGLRef.vertexMSEdgeMarkShaderID); + glDetachShader(OGLRef.programMSEdgeMarkID, OGLRef.fragmentMSEdgeMarkShaderID); + glDeleteProgram(OGLRef.programMSEdgeMarkID); + glDeleteShader(OGLRef.vertexMSEdgeMarkShaderID); + glDeleteShader(OGLRef.fragmentMSEdgeMarkShaderID); + + OGLRef.programMSEdgeMarkID = 0; + OGLRef.vertexMSEdgeMarkShaderID = 0; + OGLRef.fragmentMSEdgeMarkShaderID = 0; + } } -Render3DError OpenGLRenderer_1_2::CreateFogProgram(const OGLFogProgramKey fogProgramKey, const char *vtxShaderCString, const char *fragShaderCString) +Render3DError OpenGLRenderer_1_2::CreateFogProgram(const OGLFogProgramKey fogProgramKey, const bool isMultisample, const char *vtxShaderCString, const char *fragShaderCString) { Render3DError error = OGLERROR_NOERR; OGLRenderRef &OGLRef = *this->ref; @@ -3455,10 +3439,10 @@ Render3DError OpenGLRenderer_1_2::CreateFogProgram(const OGLFogProgramKey fogPro shaderID.fragShader = 0; error = this->ShaderProgramCreate(OGLRef.vertexFogShaderID, - shaderID.fragShader, - shaderID.program, - vtxShaderCString, - fragShaderCode.c_str()); + shaderID.fragShader, + shaderID.program, + vtxShaderCString, + fragShaderCode.c_str()); this->_fogProgramMap[fogProgramKey.key] = shaderID; @@ -3485,11 +3469,9 @@ Render3DError OpenGLRenderer_1_2::CreateFogProgram(const OGLFogProgramKey fogPro glValidateProgram(shaderID.program); glUseProgram(shaderID.program); - const GLint uniformTexGColor = glGetUniformLocation(shaderID.program, "texInFragColor"); const GLint uniformTexGDepth = glGetUniformLocation(shaderID.program, "texInFragDepth"); const GLint uniformTexGFog = glGetUniformLocation(shaderID.program, "texInFogAttributes"); const GLint uniformTexFogDensityTable = glGetUniformLocation(shaderID.program, "texFogDensityTable"); - glUniform1i(uniformTexGColor, OGLTextureUnitID_GColor); glUniform1i(uniformTexGDepth, OGLTextureUnitID_DepthStencil); glUniform1i(uniformTexGFog, OGLTextureUnitID_FogAttr); glUniform1i(uniformTexFogDensityTable, OGLTextureUnitID_LookupTable); @@ -3781,7 +3763,7 @@ Render3DError OpenGLRenderer_1_2::InitPostprocessingPrograms(const char *edgeMar if (this->isVBOSupported && this->isFBOSupported) { - error = this->CreateEdgeMarkProgram(edgeMarkVtxShaderCString, edgeMarkFragShaderCString); + error = this->CreateEdgeMarkProgram(false, edgeMarkVtxShaderCString, edgeMarkFragShaderCString); if (error != OGLERROR_NOERR) { return error; @@ -4145,6 +4127,21 @@ void OpenGLRenderer_1_2::_ResolveGeometry() glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID); } +void OpenGLRenderer_1_2::_ResolveFinalFramebuffer() +{ + OGLRenderRef &OGLRef = *this->ref; + + if (!this->_enableMultisampledRendering || (OGLRef.selectedRenderingFBO != OGLRef.fboMSIntermediateRenderID)) + { + return; + } + + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, OGLRef.fboMSIntermediateColorOutMainID); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboColorOutMainID); + glBlitFramebufferEXT(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboColorOutMainID); +} + Render3DError OpenGLRenderer_1_2::ReadBackPixels() { OGLRenderRef &OGLRef = *this->ref; @@ -4585,9 +4582,11 @@ Render3DError OpenGLRenderer_1_2::RenderGeometry() this->DisableVertexAttributes(); } - this->_ResolveGeometry(); - - this->_lastTextureDrawTarget = OGLTextureUnitID_GColor; + if (!this->_willUseMultisampleShaders) + { + this->_ResolveGeometry(); + this->_lastTextureDrawTarget = OGLTextureUnitID_GColor; + } return OGLERROR_NOERR; } @@ -4689,7 +4688,7 @@ Render3DError OpenGLRenderer_1_2::PostprocessFramebuffer() std::map::iterator it = this->_fogProgramMap.find(this->_fogProgramKey.key); if (it == this->_fogProgramMap.end()) { - Render3DError error = this->CreateFogProgram(this->_fogProgramKey, FogVtxShader_100, FogFragShader_100); + Render3DError error = this->CreateFogProgram(this->_fogProgramKey, false, FogVtxShader_100, FogFragShader_100); if (error != OGLERROR_NOERR) { return error; @@ -4734,6 +4733,12 @@ Render3DError OpenGLRenderer_1_2::EndRender() //needs to happen before endgl because it could free some textureids for expired cache items texCache.Evict(); + if (this->_willUseMultisampleShaders) + { + this->_ResolveFinalFramebuffer(); + this->_lastTextureDrawTarget = OGLTextureUnitID_GColor; + } + this->ReadBackPixels(); ENDGL(); @@ -5465,7 +5470,7 @@ Render3DError OpenGLRenderer_1_2::SetFramebufferSize(size_t w, size_t h) if (this->isVBOSupported && this->isFBOSupported) { - this->CreateEdgeMarkProgram(EdgeMarkVtxShader_100, EdgeMarkFragShader_100); + this->CreateEdgeMarkProgram(false, EdgeMarkVtxShader_100, EdgeMarkFragShader_100); } if (OGLRef.readPixelsBestFormat == GL_BGRA) diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h index 21baf8c11..e5214c918 100644 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -625,6 +625,9 @@ struct OGLRenderRef GLuint texEdgeColorTableID; GLuint texMSGColorID; GLuint texMSGWorkingID; + GLuint texMSGDepthStencilID; + GLuint texMSGPolyID; + GLuint texMSGFogAttrID; GLuint rboMSGColorID; GLuint rboMSGWorkingID; @@ -637,6 +640,7 @@ struct OGLRenderRef GLuint fboRenderMutableID; GLuint fboColorOutMainID; GLuint fboColorOutWorkingID; + GLuint fboMSIntermediateColorOutMainID; GLuint fboMSIntermediateRenderID; GLuint fboMSIntermediateRenderMutableID; GLuint selectedRenderingFBO; @@ -655,6 +659,10 @@ struct OGLRenderRef GLuint fragShaderMSGeometryZeroDstAlphaID; GLuint programMSGeometryZeroDstAlphaID; + GLuint vertexMSEdgeMarkShaderID; + GLuint fragmentMSEdgeMarkShaderID; + GLuint programMSEdgeMarkID; + GLuint vertexEdgeMarkShaderID; GLuint vertexFogShaderID; GLuint vertexFramebufferOutput6665ShaderID; @@ -825,9 +833,10 @@ protected: bool _isFBOBlitSupported; bool isMultisampledFBOSupported; bool isShaderSupported; + bool _isSampleShadingSupported; bool isVAOSupported; bool willFlipAndConvertFramebufferOnGPU; - bool willUsePerSampleZeroDstPass; + bool _willUseMultisampleShaders; bool _emulateShadowPolygon; bool _emulateSpecialZeroAlphaBlending; @@ -889,9 +898,9 @@ protected: virtual void DestroyGeometryPrograms() = 0; virtual Render3DError CreateGeometryZeroDstAlphaProgram(const char *vtxShaderCString, const char *fragShaderCString) = 0; virtual void DestroyGeometryZeroDstAlphaProgram() = 0; - virtual Render3DError CreateEdgeMarkProgram(const char *vtxShaderCString, const char *fragShaderCString) = 0; + virtual Render3DError CreateEdgeMarkProgram(const bool isMultisample, const char *vtxShaderCString, const char *fragShaderCString) = 0; virtual void DestroyEdgeMarkProgram() = 0; - virtual Render3DError CreateFogProgram(const OGLFogProgramKey fogProgramKey, const char *vtxShaderCString, const char *fragShaderCString) = 0; + virtual Render3DError CreateFogProgram(const OGLFogProgramKey fogProgramKey, const bool isMultisample, const char *vtxShaderCString, const char *fragShaderCString) = 0; virtual void DestroyFogProgram(const OGLFogProgramKey fogProgramKey) = 0; virtual void DestroyFogPrograms() = 0; virtual Render3DError CreateFramebufferOutput6665Program(const size_t outColorIndex, const char *vtxShaderCString, const char *fragShaderCString) = 0; @@ -914,6 +923,7 @@ protected: virtual Render3DError DisableVertexAttributes() = 0; virtual void _ResolveWorkingBackFacing() = 0; virtual void _ResolveGeometry() = 0; + virtual void _ResolveFinalFramebuffer() = 0; virtual Render3DError ReadBackPixels() = 0; virtual Render3DError DrawShadowPolygon(const GLenum polyPrimitive, const GLsizei vertIndexCount, const GLushort *indexBufferPtr, const bool performDepthEqualTest, const bool enableAlphaDepthWrite, const bool isTranslucent, const u8 opaquePolyID) = 0; @@ -964,9 +974,9 @@ protected: virtual void DestroyGeometryPrograms(); virtual Render3DError CreateGeometryZeroDstAlphaProgram(const char *vtxShaderCString, const char *fragShaderCString); virtual void DestroyGeometryZeroDstAlphaProgram(); - virtual Render3DError CreateEdgeMarkProgram(const char *vtxShaderCString, const char *fragShaderCString); + virtual Render3DError CreateEdgeMarkProgram(const bool isMultisample, const char *vtxShaderCString, const char *fragShaderCString); virtual void DestroyEdgeMarkProgram(); - virtual Render3DError CreateFogProgram(const OGLFogProgramKey fogProgramKey, const char *vtxShaderCString, const char *fragShaderCString); + virtual Render3DError CreateFogProgram(const OGLFogProgramKey fogProgramKey, const bool isMultisample, const char *vtxShaderCString, const char *fragShaderCString); virtual void DestroyFogProgram(const OGLFogProgramKey fogProgramKey); virtual void DestroyFogPrograms(); virtual Render3DError CreateFramebufferOutput6665Program(const size_t outColorIndex, const char *vtxShaderCString, const char *fragShaderCString); @@ -990,6 +1000,7 @@ protected: virtual Render3DError ZeroDstAlphaPass(const POLY *rawPolyList, const CPoly *clippedPolyList, const size_t clippedPolyCount, const size_t clippedPolyOpaqueCount, bool enableAlphaBlending, size_t indexOffset, POLYGON_ATTR lastPolyAttr); virtual void _ResolveWorkingBackFacing(); virtual void _ResolveGeometry(); + virtual void _ResolveFinalFramebuffer(); virtual Render3DError ReadBackPixels(); // Base rendering methods diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index dec8699d2..1f997cfbe 100644 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -447,9 +447,6 @@ void main()\n\ polyIDInfo[3] = texture(texInPolyID, texCoord[3]);\n\ polyIDInfo[4] = texture(texInPolyID, texCoord[4]);\n\ \n\ - bool isWireframe[5];\n\ - isWireframe[0] = bool(polyIDInfo[0].g);\n\ - \n\ float depth[5];\n\ depth[0] = texture(texInFragDepth, texCoord[0]).r;\n\ depth[1] = texture(texInFragDepth, texCoord[1]).r;\n\ @@ -457,6 +454,9 @@ void main()\n\ depth[3] = texture(texInFragDepth, texCoord[3]).r;\n\ depth[4] = texture(texInFragDepth, texCoord[4]).r;\n\ \n\ + bool isWireframe[5];\n\ + isWireframe[0] = bool(polyIDInfo[0].g);\n\ + \n\ outEdgeColor = vec4(0.0, 0.0, 0.0, 0.0);\n\ \n\ if (!isWireframe[0])\n\ @@ -477,47 +477,109 @@ void main()\n\ \n\ if ( ((gl_FragCoord.x >= FRAMEBUFFER_SIZE_X-1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[1]) && (depth[0] >= depth[1]) && !isWireframe[1])) )\n\ {\n\ - if (gl_FragCoord.x >= FRAMEBUFFER_SIZE_X-1.0)\n\ - {\n\ - outEdgeColor = state.edgeColor[polyID[0]/8];\n\ - }\n\ - else\n\ - {\n\ - outEdgeColor = state.edgeColor[polyID[1]/8];\n\ - }\n\ + outEdgeColor = (gl_FragCoord.x >= FRAMEBUFFER_SIZE_X-1.0) ? state.edgeColor[polyID[0]/8] : state.edgeColor[polyID[1]/8];\n\ }\n\ else if ( ((gl_FragCoord.y >= FRAMEBUFFER_SIZE_Y-1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[2]) && (depth[0] >= depth[2]) && !isWireframe[2])) )\n\ {\n\ - if (gl_FragCoord.y >= FRAMEBUFFER_SIZE_Y-1.0)\n\ - {\n\ - outEdgeColor = state.edgeColor[polyID[0]/8];\n\ - }\n\ - else\n\ - {\n\ - outEdgeColor = state.edgeColor[polyID[2]/8];\n\ - }\n\ + outEdgeColor = (gl_FragCoord.y >= FRAMEBUFFER_SIZE_Y-1.0) ? state.edgeColor[polyID[0]/8] : state.edgeColor[polyID[2]/8];\n\ }\n\ else if ( ((gl_FragCoord.x < 1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[3]) && (depth[0] >= depth[3]) && !isWireframe[3])) )\n\ {\n\ - if (gl_FragCoord.x < 1.0)\n\ - {\n\ - outEdgeColor = state.edgeColor[polyID[0]/8];\n\ - }\n\ - else\n\ - {\n\ - outEdgeColor = state.edgeColor[polyID[3]/8];\n\ - }\n\ + outEdgeColor = (gl_FragCoord.x < 1.0) ? state.edgeColor[polyID[0]/8] : state.edgeColor[polyID[3]/8];\n\ }\n\ else if ( ((gl_FragCoord.y < 1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[4]) && (depth[0] >= depth[4]) && !isWireframe[4])) )\n\ {\n\ - if (gl_FragCoord.y < 1.0)\n\ - {\n\ - outEdgeColor = state.edgeColor[polyID[0]/8];\n\ - }\n\ - else\n\ - {\n\ - outEdgeColor = state.edgeColor[polyID[4]/8];\n\ - }\n\ + outEdgeColor = (gl_FragCoord.y < 1.0) ? state.edgeColor[polyID[0]/8] : state.edgeColor[polyID[4]/8];\n\ + }\n\ + }\n\ +}\n\ +"}; + +// Vertex shader for applying edge marking, GLSL 1.50 +const char *MSEdgeMarkVtxShader_150 = {"\ +IN_VTX_POSITION vec2 inPosition;\n\ +IN_VTX_TEXCOORD0 vec2 inTexCoord0;\n\ +\n\ +void main()\n\ +{\n\ + gl_Position = vec4(inPosition, 0.0, 1.0);\n\ +}\n\ +"}; + +// Fragment shader for applying edge marking, GLSL 1.50 +const char *MSEdgeMarkFragShader_150 = {"\ +layout (std140) uniform RenderStates\n\ +{\n\ + bool enableAntialiasing;\n\ + bool enableFogAlphaOnly;\n\ + int clearPolyID;\n\ + float clearDepth;\n\ + float alphaTestRef;\n\ + float fogOffset;\n\ + float fogStep;\n\ + float pad_0;\n\ + vec4 fogColor;\n\ + vec4 edgeColor[8];\n\ + vec4 toonColor[32];\n\ +} state;\n\ +\n\ +uniform sampler2DMS texInFragDepth;\n\ +uniform sampler2DMS texInPolyID;\n\ +\n\ +OUT_COLOR vec4 outEdgeColor;\n\ +\n\ +void main()\n\ +{\n\ + vec4 polyIDInfo[5];\n\ + polyIDInfo[0] = texelFetch(texInPolyID, ivec2(gl_FragCoord.xy) + ivec2( 0, 0), gl_SampleID);\n\ + polyIDInfo[1] = texelFetch(texInPolyID, ivec2(gl_FragCoord.xy) + ivec2( 1, 0), gl_SampleID);\n\ + polyIDInfo[2] = texelFetch(texInPolyID, ivec2(gl_FragCoord.xy) + ivec2( 0, 1), gl_SampleID);\n\ + polyIDInfo[3] = texelFetch(texInPolyID, ivec2(gl_FragCoord.xy) + ivec2(-1, 0), gl_SampleID);\n\ + polyIDInfo[4] = texelFetch(texInPolyID, ivec2(gl_FragCoord.xy) + ivec2( 0,-1), gl_SampleID);\n\ + \n\ + float depth[5];\n\ + depth[0] = texelFetch(texInFragDepth, ivec2(gl_FragCoord.xy) + ivec2( 0, 0), gl_SampleID).r;\n\ + depth[1] = texelFetch(texInFragDepth, ivec2(gl_FragCoord.xy) + ivec2( 1, 0), gl_SampleID).r;\n\ + depth[2] = texelFetch(texInFragDepth, ivec2(gl_FragCoord.xy) + ivec2( 0, 1), gl_SampleID).r;\n\ + depth[3] = texelFetch(texInFragDepth, ivec2(gl_FragCoord.xy) + ivec2(-1, 0), gl_SampleID).r;\n\ + depth[4] = texelFetch(texInFragDepth, ivec2(gl_FragCoord.xy) + ivec2( 0,-1), gl_SampleID).r;\n\ + \n\ + bool isWireframe[5];\n\ + isWireframe[0] = bool(polyIDInfo[0].g);\n\ + \n\ + outEdgeColor = vec4(0.0, 0.0, 0.0, 0.0);\n\ + \n\ + if (!isWireframe[0])\n\ + {\n\ + int polyID[5];\n\ + polyID[0] = int((polyIDInfo[0].r * 63.0) + 0.5);\n\ + polyID[1] = int((polyIDInfo[1].r * 63.0) + 0.5);\n\ + polyID[2] = int((polyIDInfo[2].r * 63.0) + 0.5);\n\ + polyID[3] = int((polyIDInfo[3].r * 63.0) + 0.5);\n\ + polyID[4] = int((polyIDInfo[4].r * 63.0) + 0.5);\n\ + \n\ + isWireframe[1] = bool(polyIDInfo[1].g);\n\ + isWireframe[2] = bool(polyIDInfo[2].g);\n\ + isWireframe[3] = bool(polyIDInfo[3].g);\n\ + isWireframe[4] = bool(polyIDInfo[4].g);\n\ + \n\ + bool isEdgeMarkingClearValues = ((polyID[0] != state.clearPolyID) && (depth[0] < state.clearDepth) && !isWireframe[0]);\n\ + \n\ + if ( ((gl_FragCoord.x >= FRAMEBUFFER_SIZE_X-1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[1]) && (depth[0] >= depth[1]) && !isWireframe[1])) )\n\ + {\n\ + outEdgeColor = (gl_FragCoord.x >= FRAMEBUFFER_SIZE_X-1.0) ? state.edgeColor[polyID[0]/8] : state.edgeColor[polyID[1]/8];\n\ + }\n\ + else if ( ((gl_FragCoord.y >= FRAMEBUFFER_SIZE_Y-1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[2]) && (depth[0] >= depth[2]) && !isWireframe[2])) )\n\ + {\n\ + outEdgeColor = (gl_FragCoord.y >= FRAMEBUFFER_SIZE_Y-1.0) ? state.edgeColor[polyID[0]/8] : state.edgeColor[polyID[2]/8];\n\ + }\n\ + else if ( ((gl_FragCoord.x < 1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[3]) && (depth[0] >= depth[3]) && !isWireframe[3])) )\n\ + {\n\ + outEdgeColor = (gl_FragCoord.x < 1.0) ? state.edgeColor[polyID[0]/8] : state.edgeColor[polyID[3]/8];\n\ + }\n\ + else if ( ((gl_FragCoord.y < 1.0) ? isEdgeMarkingClearValues : ((polyID[0] != polyID[4]) && (depth[0] >= depth[4]) && !isWireframe[4])) )\n\ + {\n\ + outEdgeColor = (gl_FragCoord.y < 1.0) ? state.edgeColor[polyID[0]/8] : state.edgeColor[polyID[4]/8];\n\ }\n\ }\n\ }\n\ @@ -570,16 +632,58 @@ void main()\n\ \n\ if (polyEnableFog)\n\ {\n\ - float fogMixWeight = 0.0;\n\ - if (FOG_STEP == 0)\n\ - {\n\ - fogMixWeight = texture( texFogDensityTable, vec2( (inFragDepth <= FOG_OFFSETF) ? 0.0 : 1.0, 0.0 ) ).r;\n\ - }\n\ - else\n\ - {\n\ - fogMixWeight = texture( texFogDensityTable, vec2( (inFragDepth * (1024.0/float(FOG_STEP))) + (((-float(FOG_OFFSET)/float(FOG_STEP)) - 0.5) / 32.0), 0.0 ) ).r;\n\ - }\n\ - \n\ + float densitySelect = (FOG_STEP == 0) ? ((inFragDepth <= FOG_OFFSETF) ? 0.0 : 1.0) : (inFragDepth * (1024.0/float(FOG_STEP))) + (((-float(FOG_OFFSET)/float(FOG_STEP)) - 0.5) / 32.0);\n\ + float fogMixWeight = texture( texFogDensityTable, vec2(densitySelect, 0.0) ).r;\n\ + outFogWeight = (state.enableFogAlphaOnly) ? vec4(vec3(0.0), fogMixWeight) : vec4(fogMixWeight);\n\ + }\n\ +}\n\ +"}; + +// Vertex shader for applying fog, GLSL 1.50 +const char *MSFogVtxShader_150 = {"\ +IN_VTX_POSITION vec2 inPosition;\n\ +IN_VTX_TEXCOORD0 vec2 inTexCoord0;\n\ +\n\ +void main()\n\ +{\n\ + gl_Position = vec4(inPosition, 0.0, 1.0);\n\ +}\n\ +"}; + +// Fragment shader for applying fog, GLSL 1.50 +const char *MSFogFragShader_150 = {"\ +layout (std140) uniform RenderStates\n\ +{\n\ + bool enableAntialiasing;\n\ + bool enableFogAlphaOnly;\n\ + int clearPolyID;\n\ + float clearDepth;\n\ + float alphaTestRef;\n\ + float fogOffset;\n\ + float fogStep;\n\ + float pad_0;\n\ + vec4 fogColor;\n\ + vec4 edgeColor[8];\n\ + vec4 toonColor[32];\n\ +} state;\n\ +\n\ +uniform sampler2DMS texInFragDepth;\n\ +uniform sampler2DMS texInFogAttributes;\n\ +uniform sampler2D texFogDensityTable;\n\ +\n\ +OUT_COLOR vec4 outFogWeight;\n\ +\n\ +void main()\n\ +{\n\ + float inFragDepth = texelFetch(texInFragDepth, ivec2(gl_FragCoord.xy), gl_SampleID).r;\n\ + vec4 inFogAttributes = texelFetch(texInFogAttributes, ivec2(gl_FragCoord.xy), gl_SampleID);\n\ + bool polyEnableFog = (inFogAttributes.r > 0.999);\n\ + outFogWeight = vec4(0.0);\n\ + \n\ + if (polyEnableFog)\n\ + {\n\ + float densitySelect = (FOG_STEP == 0) ? ((inFragDepth <= FOG_OFFSETF) ? 0.0 : 1.0) : (inFragDepth * (1024.0/float(FOG_STEP))) + (((-float(FOG_OFFSET)/float(FOG_STEP)) - 0.5) / 32.0);\n\ + float fogMixWeight = texture( texFogDensityTable, vec2(densitySelect, 0.0) ).r;\n\ outFogWeight = (state.enableFogAlphaOnly) ? vec4(vec3(0.0), fogMixWeight) : vec4(fogMixWeight);\n\ }\n\ }\n\ @@ -632,7 +736,6 @@ OpenGLRenderer_3_2::OpenGLRenderer_3_2() _is64kUBOSupported = false; _isTBOSupported = false; _isShaderFixedLocationSupported = false; - _isSampleShadingSupported = false; _isConservativeDepthSupported = false; _isConservativeDepthAMDSupported = false; _syncBufferSetup = NULL; @@ -733,21 +836,10 @@ Render3DError OpenGLRenderer_3_2::InitExtensions() if (this->_isSampleShadingSupported) { error = this->CreateMSGeometryZeroDstAlphaProgram(GeometryZeroDstAlphaPixelMaskVtxShader_150, MSGeometryZeroDstAlphaPixelMaskFragShader_150); - if (error == OGLERROR_NOERR) - { - this->willUsePerSampleZeroDstPass = true; - } - else - { - glUseProgram(0); - this->DestroyGeometryPrograms(); - this->DestroyGeometryZeroDstAlphaProgram(); - this->isShaderSupported = false; - this->_isSampleShadingSupported = false; - this->willUsePerSampleZeroDstPass = false; - - return error; - } + this->_isSampleShadingSupported = (error == OGLERROR_NOERR); + + error = this->CreateEdgeMarkProgram(true, MSEdgeMarkVtxShader_150, MSEdgeMarkFragShader_150); + this->_isSampleShadingSupported = this->_isSampleShadingSupported && (error == OGLERROR_NOERR); } INFO("OpenGL: Successfully created geometry shaders.\n"); @@ -827,6 +919,7 @@ Render3DError OpenGLRenderer_3_2::InitExtensions() this->_isDepthLEqualPolygonFacingSupported = true; this->_enableMultisampledRendering = ((this->_selectedMultisampleSize >= 2) && this->isMultisampledFBOSupported); + this->_willUseMultisampleShaders = this->_isSampleShadingSupported && this->_enableMultisampledRendering; this->InitFinalRenderStates(&oglExtensionSet); // This must be done last @@ -1065,16 +1158,14 @@ Render3DError OpenGLRenderer_3_2::CreateMultisampledFBO(GLsizei numSamples) { OGLRenderRef &OGLRef = *this->ref; - // Set up FBO render targets - glGenRenderbuffers(1, &OGLRef.rboMSGPolyID); - glGenRenderbuffers(1, &OGLRef.rboMSGFogAttrID); - glGenRenderbuffers(1, &OGLRef.rboMSGDepthStencilID); - #ifdef GL_VERSION_3_2 - if (this->willUsePerSampleZeroDstPass) + if (this->_isSampleShadingSupported) { glGenTextures(1, &OGLRef.texMSGColorID); glGenTextures(1, &OGLRef.texMSGWorkingID); + glGenTextures(1, &OGLRef.texMSGDepthStencilID); + glGenTextures(1, &OGLRef.texMSGPolyID); + glGenTextures(1, &OGLRef.texMSGFogAttrID); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GColor); glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGColorID); @@ -1084,6 +1175,18 @@ Render3DError OpenGLRenderer_3_2::CreateMultisampledFBO(GLsizei numSamples) glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGWorkingID); glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, numSamples, GL_RGBA8, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, GL_TRUE); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_DepthStencil); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGDepthStencilID); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, numSamples, GL_DEPTH24_STENCIL8, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, GL_TRUE); + + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GPolyID); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGPolyID); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, numSamples, GL_RGBA8, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, GL_TRUE); + + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGFogAttrID); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, numSamples, GL_RGBA8, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight, GL_TRUE); + glActiveTexture(GL_TEXTURE0); } else @@ -1091,42 +1194,76 @@ Render3DError OpenGLRenderer_3_2::CreateMultisampledFBO(GLsizei numSamples) { glGenRenderbuffers(1, &OGLRef.rboMSGColorID); glGenRenderbuffers(1, &OGLRef.rboMSGWorkingID); + glGenRenderbuffers(1, &OGLRef.rboMSGDepthStencilID); + glGenRenderbuffers(1, &OGLRef.rboMSGPolyID); + glGenRenderbuffers(1, &OGLRef.rboMSGFogAttrID); glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGColorID); glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA8, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight); glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGWorkingID); glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA8, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight); + glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilID); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_DEPTH24_STENCIL8, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight); + glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGPolyID); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA8, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight); + glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGFogAttrID); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA8, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight); } - glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGPolyID); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA8, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight); - glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGFogAttrID); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA8, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight); - glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilID); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_DEPTH24_STENCIL8, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight); - // Set up multisampled rendering FBO + glGenFramebuffers(1, &OGLRef.fboMSIntermediateColorOutMainID); glGenFramebuffers(1, &OGLRef.fboMSIntermediateRenderID); glGenFramebuffers(1, &OGLRef.fboMSIntermediateRenderMutableID); + glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboMSIntermediateColorOutMainID); + +#ifdef GL_VERSION_3_2 + if (this->_isSampleShadingSupported) + { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGColorID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGWorkingID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGDepthStencilID, 0); + } + else +#endif + { + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, OGLRef.rboMSGColorID); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_RENDERBUFFER, OGLRef.rboMSGWorkingID); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilID); + } + + 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; + } + + glDrawBuffer(GL_COLOR_ATTACHMENT0); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboMSIntermediateRenderID); #ifdef GL_VERSION_3_2 - if (this->willUsePerSampleZeroDstPass) + if (this->_isSampleShadingSupported) { glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGColorID, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_WORKING_ATTACHMENT_ID, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGWorkingID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGDepthStencilID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_POLYID_ATTACHMENT_ID, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGPolyID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_FOGATTRIBUTES_ATTACHMENT_ID, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGFogAttrID, 0); } else #endif { glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_COLOROUT_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGColorID); glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_WORKING_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGWorkingID); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilID); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_POLYID_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGPolyID); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_FOGATTRIBUTES_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGFogAttrID); } - glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_POLYID_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGPolyID); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_FOGATTRIBUTES_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGFogAttrID); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilID); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { @@ -1136,25 +1273,30 @@ Render3DError OpenGLRenderer_3_2::CreateMultisampledFBO(GLsizei numSamples) return OGLERROR_FBO_CREATE_ERROR; } + glDrawBuffer(GL_COLOR_ATTACHMENT0); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboMSIntermediateRenderMutableID); #ifdef GL_VERSION_3_2 - if (this->willUsePerSampleZeroDstPass) + if (this->_isSampleShadingSupported) { glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGColorID, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_WORKING_ATTACHMENT_ID, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGWorkingID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGDepthStencilID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_POLYID_ATTACHMENT_ID, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGPolyID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, OGL_FOGATTRIBUTES_ATTACHMENT_ID, GL_TEXTURE_2D_MULTISAMPLE, OGLRef.texMSGFogAttrID, 0); } else #endif { glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_COLOROUT_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGColorID); glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_WORKING_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGWorkingID); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilID); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_POLYID_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGPolyID); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_FOGATTRIBUTES_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGFogAttrID); } - glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_POLYID_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGPolyID); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, OGL_FOGATTRIBUTES_ATTACHMENT_ID, GL_RENDERBUFFER, OGLRef.rboMSGFogAttrID); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilID); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { INFO("OpenGL: Failed to create multisampled FBO. Multisample antialiasing will be disabled.\n"); @@ -1163,6 +1305,9 @@ Render3DError OpenGLRenderer_3_2::CreateMultisampledFBO(GLsizei numSamples) return OGLERROR_FBO_CREATE_ERROR; } + glDrawBuffer(GL_COLOR_ATTACHMENT0); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboRenderID); INFO("OpenGL: Successfully created multisampled FBO.\n"); @@ -1179,19 +1324,28 @@ void OpenGLRenderer_3_2::DestroyMultisampledFBO() OGLRenderRef &OGLRef = *this->ref; glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &OGLRef.fboMSIntermediateColorOutMainID); glDeleteFramebuffers(1, &OGLRef.fboMSIntermediateRenderID); glDeleteFramebuffers(1, &OGLRef.fboMSIntermediateRenderMutableID); glDeleteTextures(1, &OGLRef.texMSGColorID); glDeleteTextures(1, &OGLRef.texMSGWorkingID); + glDeleteTextures(1, &OGLRef.texMSGDepthStencilID); + glDeleteTextures(1, &OGLRef.texMSGPolyID); + glDeleteTextures(1, &OGLRef.texMSGFogAttrID); glDeleteRenderbuffers(1, &OGLRef.rboMSGColorID); glDeleteRenderbuffers(1, &OGLRef.rboMSGWorkingID); glDeleteRenderbuffers(1, &OGLRef.rboMSGPolyID); glDeleteRenderbuffers(1, &OGLRef.rboMSGFogAttrID); glDeleteRenderbuffers(1, &OGLRef.rboMSGDepthStencilID); + OGLRef.fboMSIntermediateColorOutMainID = 0; OGLRef.fboMSIntermediateRenderID = 0; + OGLRef.fboMSIntermediateRenderMutableID = 0; OGLRef.texMSGColorID = 0; OGLRef.texMSGWorkingID = 0; + OGLRef.texMSGDepthStencilID = 0; + OGLRef.texMSGPolyID = 0; + OGLRef.texMSGFogAttrID = 0; OGLRef.rboMSGColorID = 0; OGLRef.rboMSGWorkingID = 0; OGLRef.rboMSGPolyID = 0; @@ -1222,12 +1376,18 @@ void OpenGLRenderer_3_2::ResizeMultisampledFBOs(GLsizei numSamples) } #ifdef GL_VERSION_3_2 - if (this->willUsePerSampleZeroDstPass) + if (this->_isSampleShadingSupported) { glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GColor); glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, numSamples, GL_RGBA8, w, h, GL_TRUE); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FinalColor); glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, numSamples, GL_RGBA8, w, h, GL_TRUE); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_DepthStencil); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, numSamples, GL_DEPTH24_STENCIL8, w, h, GL_TRUE); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GPolyID); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, numSamples, GL_RGBA8, w, h, GL_TRUE); + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, numSamples, GL_RGBA8, w, h, GL_TRUE); glActiveTexture(GL_TEXTURE0); } else @@ -1237,14 +1397,13 @@ void OpenGLRenderer_3_2::ResizeMultisampledFBOs(GLsizei numSamples) glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA8, w, h); glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGWorkingID); glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA8, w, h); + glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilID); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_DEPTH24_STENCIL8, w, h); + glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGPolyID); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA8, w, h); + glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGFogAttrID); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA8, w, h); } - - glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGPolyID); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA8, w, h); - glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGFogAttrID); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_RGBA8, w, h); - glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilID); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, numSamples, GL_DEPTH24_STENCIL8, w, h); } Render3DError OpenGLRenderer_3_2::CreateVAOs() @@ -1737,7 +1896,7 @@ void OpenGLRenderer_3_2::DestroyMSGeometryZeroDstAlphaProgram() OGLRef.fragShaderMSGeometryZeroDstAlphaID = 0; } -Render3DError OpenGLRenderer_3_2::CreateEdgeMarkProgram(const char *vtxShaderCString, const char *fragShaderCString) +Render3DError OpenGLRenderer_3_2::CreateEdgeMarkProgram(const bool isMultisample, const char *vtxShaderCString, const char *fragShaderCString) { Render3DError error = OGLERROR_NOERR; OGLRenderRef &OGLRef = *this->ref; @@ -1756,6 +1915,12 @@ Render3DError OpenGLRenderer_3_2::CreateEdgeMarkProgram(const char *vtxShaderCSt { shaderHeader << "#version 150\n"; } + + if (isMultisample) + { + shaderHeader << "#extension GL_ARB_sample_shading : require\n"; + } + shaderHeader << "\n"; shaderHeader << "#define FRAMEBUFFER_SIZE_X " << this->_framebufferWidth << ".0 \n"; shaderHeader << "#define FRAMEBUFFER_SIZE_Y " << this->_framebufferHeight << ".0 \n"; @@ -1787,12 +1952,29 @@ Render3DError OpenGLRenderer_3_2::CreateEdgeMarkProgram(const char *vtxShaderCSt std::string vtxShaderCode = shaderHeader.str() + vsHeader.str() + std::string(vtxShaderCString); std::string fragShaderCode = shaderHeader.str() + fsHeader.str() + std::string(fragShaderCString); + GLuint programID = 0; + + if (isMultisample) + { + error = this->ShaderProgramCreate(OGLRef.vertexMSEdgeMarkShaderID, + OGLRef.fragmentMSEdgeMarkShaderID, + OGLRef.programMSEdgeMarkID, + vtxShaderCode.c_str(), + fragShaderCode.c_str()); + + programID = OGLRef.programMSEdgeMarkID; + } + else + { + error = this->ShaderProgramCreate(OGLRef.vertexEdgeMarkShaderID, + OGLRef.fragmentEdgeMarkShaderID, + OGLRef.programEdgeMarkID, + vtxShaderCode.c_str(), + fragShaderCode.c_str()); + + programID = OGLRef.programEdgeMarkID; + } - error = this->ShaderProgramCreate(OGLRef.vertexEdgeMarkShaderID, - OGLRef.fragmentEdgeMarkShaderID, - OGLRef.programEdgeMarkID, - vtxShaderCode.c_str(), - fragShaderCode.c_str()); if (error != OGLERROR_NOERR) { INFO("OpenGL: Failed to create the EDGE MARK shader program.\n"); @@ -1804,14 +1986,14 @@ Render3DError OpenGLRenderer_3_2::CreateEdgeMarkProgram(const char *vtxShaderCSt #if defined(GL_VERSION_3_0) if (!this->_isShaderFixedLocationSupported) { - glBindAttribLocation(OGLRef.programEdgeMarkID, OGLVertexAttributeID_Position, "inPosition"); - glBindAttribLocation(OGLRef.programEdgeMarkID, OGLVertexAttributeID_TexCoord0, "inTexCoord0"); - glBindFragDataLocation(OGLRef.programEdgeMarkID, 0, "outEdgeColor"); + glBindAttribLocation(programID, OGLVertexAttributeID_Position, "inPosition"); + glBindAttribLocation(programID, OGLVertexAttributeID_TexCoord0, "inTexCoord0"); + glBindFragDataLocation(programID, 0, "outEdgeColor"); } #endif - glLinkProgram(OGLRef.programEdgeMarkID); - if (!this->ValidateShaderProgramLink(OGLRef.programEdgeMarkID)) + glLinkProgram(programID); + if (!this->ValidateShaderProgramLink(programID)) { INFO("OpenGL: Failed to link the EDGE MARK shader program.\n"); glUseProgram(0); @@ -1819,21 +2001,21 @@ Render3DError OpenGLRenderer_3_2::CreateEdgeMarkProgram(const char *vtxShaderCSt return OGLERROR_SHADER_CREATE_ERROR; } - glValidateProgram(OGLRef.programEdgeMarkID); - glUseProgram(OGLRef.programEdgeMarkID); + glValidateProgram(programID); + glUseProgram(programID); - const GLuint uniformBlockRenderStates = glGetUniformBlockIndex(OGLRef.programEdgeMarkID, "RenderStates"); - glUniformBlockBinding(OGLRef.programEdgeMarkID, uniformBlockRenderStates, OGLBindingPointID_RenderStates); + const GLuint uniformBlockRenderStates = glGetUniformBlockIndex(programID, "RenderStates"); + glUniformBlockBinding(programID, uniformBlockRenderStates, OGLBindingPointID_RenderStates); - const GLint uniformTexGDepth = glGetUniformLocation(OGLRef.programEdgeMarkID, "texInFragDepth"); - const GLint uniformTexGPolyID = glGetUniformLocation(OGLRef.programEdgeMarkID, "texInPolyID"); + const GLint uniformTexGDepth = glGetUniformLocation(programID, "texInFragDepth"); + const GLint uniformTexGPolyID = glGetUniformLocation(programID, "texInPolyID"); glUniform1i(uniformTexGDepth, OGLTextureUnitID_DepthStencil); glUniform1i(uniformTexGPolyID, OGLTextureUnitID_GPolyID); return OGLERROR_NOERR; } -Render3DError OpenGLRenderer_3_2::CreateFogProgram(const OGLFogProgramKey fogProgramKey, const char *vtxShaderCString, const char *fragShaderCString) +Render3DError OpenGLRenderer_3_2::CreateFogProgram(const OGLFogProgramKey fogProgramKey, const bool isMultisample, const char *vtxShaderCString, const char *fragShaderCString) { Render3DError error = OGLERROR_NOERR; OGLRenderRef &OGLRef = *this->ref; @@ -1864,6 +2046,12 @@ Render3DError OpenGLRenderer_3_2::CreateFogProgram(const OGLFogProgramKey fogPro { shaderHeader << "#version 150\n"; } + + if (isMultisample) + { + shaderHeader << "#extension GL_ARB_sample_shading : require\n"; + } + shaderHeader << "\n"; std::stringstream vsHeader; @@ -1903,10 +2091,10 @@ Render3DError OpenGLRenderer_3_2::CreateFogProgram(const OGLFogProgramKey fogPro shaderID.fragShader = 0; error = this->ShaderProgramCreate(OGLRef.vertexFogShaderID, - shaderID.fragShader, - shaderID.program, - vtxShaderCode.c_str(), - fragShaderCode.c_str()); + shaderID.fragShader, + shaderID.program, + vtxShaderCode.c_str(), + fragShaderCode.c_str()); this->_fogProgramMap[fogProgramKey.key] = shaderID; @@ -2107,8 +2295,8 @@ Render3DError OpenGLRenderer_3_2::ZeroDstAlphaPass(const POLY *rawPolyList, cons this->DisableVertexAttributes(); - 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. + const bool isRunningMSAA = this->_enableMultisampledRendering && (OGLRef.selectedRenderingFBO == OGLRef.fboMSIntermediateRenderID); + const bool isRunningMSAAWithPerSampleShading = isRunningMSAA && this->_willUseMultisampleShaders; // Doing per-sample shading will be more accurate than not doing so. if (isRunningMSAA && !isRunningMSAAWithPerSampleShading) { @@ -2181,7 +2369,7 @@ void OpenGLRenderer_3_2::_ResolveWorkingBackFacing() { OGLRenderRef &OGLRef = *this->ref; - if (!this->_emulateDepthLEqualPolygonFacing || !this->isMultisampledFBOSupported || (OGLRef.selectedRenderingFBO != OGLRef.fboMSIntermediateRenderID)) + if (!this->_emulateDepthLEqualPolygonFacing || !this->_enableMultisampledRendering || (OGLRef.selectedRenderingFBO != OGLRef.fboMSIntermediateRenderID)) { return; } @@ -2200,7 +2388,7 @@ void OpenGLRenderer_3_2::_ResolveGeometry() { OGLRenderRef &OGLRef = *this->ref; - if (!this->isMultisampledFBOSupported || (OGLRef.selectedRenderingFBO != OGLRef.fboMSIntermediateRenderID)) + if (!this->_enableMultisampledRendering || (OGLRef.selectedRenderingFBO != OGLRef.fboMSIntermediateRenderID)) { return; } @@ -2231,6 +2419,21 @@ void OpenGLRenderer_3_2::_ResolveGeometry() glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboRenderID); } +void OpenGLRenderer_3_2::_ResolveFinalFramebuffer() +{ + OGLRenderRef &OGLRef = *this->ref; + + if (!this->_enableMultisampledRendering || (OGLRef.selectedRenderingFBO != OGLRef.fboMSIntermediateRenderID)) + { + return; + } + + glBindFramebuffer(GL_READ_FRAMEBUFFER, OGLRef.fboMSIntermediateColorOutMainID); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OGLRef.fboColorOutMainID); + glBlitFramebuffer(0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboColorOutMainID); +} + Render3DError OpenGLRenderer_3_2::ReadBackPixels() { OGLRenderRef &OGLRef = *this->ref; @@ -2544,7 +2747,8 @@ Render3DError OpenGLRenderer_3_2::PostprocessFramebuffer() OGLRenderRef &OGLRef = *this->ref; // Set up the postprocessing states - glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboColorOutMainID); + const GLuint fboPostprocess = (this->_willUseMultisampleShaders) ? OGLRef.fboMSIntermediateColorOutMainID : OGLRef.fboColorOutMainID; + glBindFramebuffer(GL_FRAMEBUFFER, fboPostprocess); glViewport(0, 0, (GLsizei)this->_framebufferWidth, (GLsizei)this->_framebufferHeight); glDisable(GL_DEPTH_TEST); @@ -2553,6 +2757,20 @@ Render3DError OpenGLRenderer_3_2::PostprocessFramebuffer() if (this->_enableEdgeMark) { + GLuint pGZeroDstAlphaID = 0; + GLuint pEdgeMarkID = 0; + + if (this->_willUseMultisampleShaders) + { + pGZeroDstAlphaID = OGLRef.programMSGeometryZeroDstAlphaID; + pEdgeMarkID = OGLRef.programMSEdgeMarkID; + } + else + { + pGZeroDstAlphaID = OGLRef.programGeometryZeroDstAlphaID; + pEdgeMarkID = OGLRef.programEdgeMarkID; + } + if (this->_needsZeroDstAlphaPass && this->_emulateSpecialZeroAlphaBlending) { // Pass 1: Determine the pixels with zero alpha @@ -2563,12 +2781,12 @@ Render3DError OpenGLRenderer_3_2::PostprocessFramebuffer() glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glStencilMask(0x40); - glUseProgram(OGLRef.programGeometryZeroDstAlphaID); + glUseProgram(pGZeroDstAlphaID); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // Pass 2: Unblended edge mark colors to zero-alpha pixels glDrawBuffer(OGL_COLOROUT_ATTACHMENT_ID); - glUseProgram(OGLRef.programEdgeMarkID); + glUseProgram(pEdgeMarkID); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); glStencilFunc(GL_NOTEQUAL, 0x40, 0x40); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); @@ -2581,7 +2799,7 @@ Render3DError OpenGLRenderer_3_2::PostprocessFramebuffer() } else { - glUseProgram(OGLRef.programEdgeMarkID); + glUseProgram(pEdgeMarkID); glEnable(GL_BLEND); glDisable(GL_STENCIL_TEST); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); @@ -2594,7 +2812,17 @@ Render3DError OpenGLRenderer_3_2::PostprocessFramebuffer() std::map::iterator it = this->_fogProgramMap.find(this->_fogProgramKey.key); if (it == this->_fogProgramMap.end()) { - Render3DError error = this->CreateFogProgram(this->_fogProgramKey, FogVtxShader_150, FogFragShader_150); + Render3DError error = OGLERROR_NOERR; + + if (this->_willUseMultisampleShaders) + { + error = this->CreateFogProgram(this->_fogProgramKey, true, MSFogVtxShader_150, MSFogFragShader_150); + } + else + { + error = this->CreateFogProgram(this->_fogProgramKey, false, FogVtxShader_150, FogFragShader_150); + } + if (error != OGLERROR_NOERR) { return error; @@ -2607,9 +2835,9 @@ Render3DError OpenGLRenderer_3_2::PostprocessFramebuffer() glBlendFuncSeparate(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_CONSTANT_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); glBlendColor( this->_pendingRenderStates.fogColor.r, - this->_pendingRenderStates.fogColor.g, - this->_pendingRenderStates.fogColor.b, - this->_pendingRenderStates.fogColor.a ); + this->_pendingRenderStates.fogColor.g, + this->_pendingRenderStates.fogColor.b, + this->_pendingRenderStates.fogColor.a ); glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); @@ -2697,8 +2925,6 @@ Render3DError OpenGLRenderer_3_2::ClearUsingImage(const u16 *__restrict colorBuf Render3DError OpenGLRenderer_3_2::ClearUsingValues(const Color4u8 &clearColor6665, const FragmentAttributes &clearAttributes) { - OGLRenderRef &OGLRef = *this->ref; - const GLfloat oglColor[4] = {divide6bitBy63_LUT[clearColor6665.r], divide6bitBy63_LUT[clearColor6665.g], divide6bitBy63_LUT[clearColor6665.b], divide5bitBy31_LUT[clearColor6665.a]}; glClearBufferfv(GL_COLOR, 0, oglColor); glClearBufferfi(GL_DEPTH_STENCIL, 0, (GLfloat)clearAttributes.depth / (GLfloat)0x00FFFFFF, clearAttributes.opaquePolyID); @@ -2907,16 +3133,30 @@ Render3DError OpenGLRenderer_3_2::SetFramebufferSize(size_t w, size_t h) this->DestroyFramebufferOutput6665Programs(); this->DestroyMSGeometryZeroDstAlphaProgram(); - this->CreateEdgeMarkProgram(EdgeMarkVtxShader_150, EdgeMarkFragShader_150); - this->CreateFramebufferOutput6665Program(0, FramebufferOutputVtxShader_150, FramebufferOutput6665FragShader_150); - this->CreateFramebufferOutput6665Program(1, FramebufferOutputVtxShader_150, FramebufferOutput6665FragShader_150); + this->CreateEdgeMarkProgram(false, EdgeMarkVtxShader_150, EdgeMarkFragShader_150); + const bool oldMultisampleShadingFlag = this->_willUseMultisampleShaders; if (this->_isSampleShadingSupported) { Render3DError shaderError = this->CreateMSGeometryZeroDstAlphaProgram(GeometryZeroDstAlphaPixelMaskVtxShader_150, MSGeometryZeroDstAlphaPixelMaskFragShader_150); - this->willUsePerSampleZeroDstPass = (shaderError == OGLERROR_NOERR); + this->_isSampleShadingSupported = (shaderError == OGLERROR_NOERR); + + shaderError = this->CreateEdgeMarkProgram(true, MSEdgeMarkVtxShader_150, MSEdgeMarkFragShader_150); + this->_isSampleShadingSupported = this->_isSampleShadingSupported && (shaderError == OGLERROR_NOERR); + + this->_willUseMultisampleShaders = this->_isSampleShadingSupported && this->_enableMultisampledRendering; } + if (this->_willUseMultisampleShaders != oldMultisampleShadingFlag) + { + // If, for some reason or another, this flag gets changed due to a shader compilation error, + // then reset all fog shader programs now. + this->DestroyFogPrograms(); + } + + this->CreateFramebufferOutput6665Program(0, FramebufferOutputVtxShader_150, FramebufferOutput6665FragShader_150); + this->CreateFramebufferOutput6665Program(1, FramebufferOutputVtxShader_150, FramebufferOutput6665FragShader_150); + // Call ResizeMultisampledFBOs() after _framebufferWidth and _framebufferHeight are set // since this method depends on them. GLsizei sampleSize = this->GetLimitedMultisampleSize(); diff --git a/desmume/src/OGLRender_3_2.h b/desmume/src/OGLRender_3_2.h index ee47a905a..8b36f6c08 100644 --- a/desmume/src/OGLRender_3_2.h +++ b/desmume/src/OGLRender_3_2.h @@ -64,7 +64,6 @@ protected: bool _is64kUBOSupported; bool _isTBOSupported; bool _isShaderFixedLocationSupported; - bool _isSampleShadingSupported; bool _isConservativeDepthSupported; bool _isConservativeDepthAMDSupported; @@ -85,8 +84,8 @@ protected: virtual Render3DError CreateGeometryZeroDstAlphaProgram(const char *vtxShaderCString, const char *fragShaderCString); virtual Render3DError CreateMSGeometryZeroDstAlphaProgram(const char *vtxShaderCString, const char *fragShaderCString); virtual void DestroyMSGeometryZeroDstAlphaProgram(); - virtual Render3DError CreateEdgeMarkProgram(const char *vtxShaderCString, const char *fragShaderCString); - virtual Render3DError CreateFogProgram(const OGLFogProgramKey fogProgramKey, const char *vtxShaderCString, const char *fragShaderCString); + virtual Render3DError CreateEdgeMarkProgram(const bool isMultisample, const char *vtxShaderCString, const char *fragShaderCString); + virtual Render3DError CreateFogProgram(const OGLFogProgramKey fogProgramKey, const bool isMultisample, const char *vtxShaderCString, const char *fragShaderCString); virtual Render3DError CreateFramebufferOutput6665Program(const size_t outColorIndex, const char *vtxShaderCString, const char *fragShaderCString); virtual Render3DError CreateFramebufferOutput8888Program(const size_t outColorIndex, const char *vtxShaderCString, const char *fragShaderCString); @@ -97,6 +96,7 @@ protected: virtual Render3DError ZeroDstAlphaPass(const POLY *rawPolyList, const CPoly *clippedPolyList, const size_t clippedPolyCount, const size_t clippedPolyOpaqueCount, bool enableAlphaBlending, size_t indexOffset, POLYGON_ATTR lastPolyAttr); virtual void _ResolveWorkingBackFacing(); virtual void _ResolveGeometry(); + virtual void _ResolveFinalFramebuffer(); virtual Render3DError ReadBackPixels(); virtual Render3DError BeginRender(const GFX3D_State &renderState, const GFX3D_GeometryList &renderGList); virtual Render3DError PostprocessFramebuffer(); diff --git a/desmume/src/OGLRender_ES3.cpp b/desmume/src/OGLRender_ES3.cpp index 0721bd79e..63d802e1a 100644 --- a/desmume/src/OGLRender_ES3.cpp +++ b/desmume/src/OGLRender_ES3.cpp @@ -677,7 +677,7 @@ Render3DError OpenGLESRenderer_3_0::CreateGeometryZeroDstAlphaProgram(const char return OGLERROR_NOERR; } -Render3DError OpenGLESRenderer_3_0::CreateEdgeMarkProgram(const char *vtxShaderCString, const char *fragShaderCString) +Render3DError OpenGLESRenderer_3_0::CreateEdgeMarkProgram(const bool isMultisample, const char *vtxShaderCString, const char *fragShaderCString) { Render3DError error = OGLERROR_NOERR; OGLRenderRef &OGLRef = *this->ref; @@ -743,7 +743,7 @@ Render3DError OpenGLESRenderer_3_0::CreateEdgeMarkProgram(const char *vtxShaderC return OGLERROR_NOERR; } -Render3DError OpenGLESRenderer_3_0::CreateFogProgram(const OGLFogProgramKey fogProgramKey, const char *vtxShaderCString, const char *fragShaderCString) +Render3DError OpenGLESRenderer_3_0::CreateFogProgram(const OGLFogProgramKey fogProgramKey, const bool isMultisample, const char *vtxShaderCString, const char *fragShaderCString) { Render3DError error = OGLERROR_NOERR; OGLRenderRef &OGLRef = *this->ref; diff --git a/desmume/src/OGLRender_ES3.h b/desmume/src/OGLRender_ES3.h index 86c05933a..4a492b4f8 100644 --- a/desmume/src/OGLRender_ES3.h +++ b/desmume/src/OGLRender_ES3.h @@ -45,8 +45,8 @@ class OpenGLESRenderer_3_0 : public OpenGLRenderer_3_2 protected: virtual Render3DError CreateGeometryPrograms(); virtual Render3DError CreateGeometryZeroDstAlphaProgram(const char *vtxShaderCString, const char *fragShaderCString); - virtual Render3DError CreateEdgeMarkProgram(const char *vtxShaderCString, const char *fragShaderCString); - virtual Render3DError CreateFogProgram(const OGLFogProgramKey fogProgramKey, const char *vtxShaderCString, const char *fragShaderCString); + virtual Render3DError CreateEdgeMarkProgram(const bool isMultisample, const char *vtxShaderCString, const char *fragShaderCString); + virtual Render3DError CreateFogProgram(const OGLFogProgramKey fogProgramKey, const bool isMultisample, const char *vtxShaderCString, const char *fragShaderCString); virtual Render3DError CreateFramebufferOutput6665Program(const size_t outColorIndex, const char *vtxShaderCString, const char *fragShaderCString); public: