diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 694ff77c0..e4021e105 100755 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -339,11 +339,11 @@ void main() \n\ mat2 texScaleMtx = mat2( vec2(polyTexScale.x, 0.0), \n\ vec2( 0.0, polyTexScale.y)); \n\ \n\ - vtxTexCoord = texScaleMtx * inTexCoord0; \n\ + vtxTexCoord = (texScaleMtx * inTexCoord0) / 16.0; \n\ vtxColor = vec4(inColor / 63.0, polyAlpha); \n\ isPolyDrawable = ((polyMode != 3) || polyDrawShadow) ? 1.0 : -1.0;\n\ \n\ - gl_Position = inPosition;\n\ + gl_Position = inPosition / 4096.0;\n\ } \n\ "}; @@ -367,20 +367,21 @@ uniform bool polyEnableTexture;\n\ uniform bool polyEnableFog;\n\ uniform bool texDrawOpaque;\n\ uniform bool texSingleBitAlpha;\n\ +uniform bool polyIsBackFacing;\n\ \n\ uniform bool drawModeDepthEqualsTest;\n\ uniform bool polyDrawShadow;\n\ uniform float polyDepthOffset;\n\ \n\ #if USE_DEPTH_LEQUAL_POLYGON_FACING && !DRAW_MODE_OPAQUE\n\ -uniform sampler2D inBackFacing;\n\ +uniform sampler2D inDstBackFacing;\n\ #endif\n\ \n\ void main()\n\ {\n\ #if USE_DEPTH_LEQUAL_POLYGON_FACING && !DRAW_MODE_OPAQUE\n\ - bool isOpaqueDstBackFacing = bool( texture2D(inBackFacing, vec2(gl_FragCoord.x/FRAMEBUFFER_SIZE_X, gl_FragCoord.y/FRAMEBUFFER_SIZE_Y)).r );\n\ - if (drawModeDepthEqualsTest && (!gl_FrontFacing || !isOpaqueDstBackFacing))\n\ + bool isOpaqueDstBackFacing = bool( texture2D(inDstBackFacing, vec2(gl_FragCoord.x/FRAMEBUFFER_SIZE_X, gl_FragCoord.y/FRAMEBUFFER_SIZE_Y)).r );\n\ + if (drawModeDepthEqualsTest && (polyIsBackFacing || !isOpaqueDstBackFacing))\n\ {\n\ discard;\n\ }\n\ @@ -445,7 +446,7 @@ void main()\n\ gl_FragData[ATTACHMENT_FOG_ATTRIBUTES] = (isPolyDrawable > 0.0) ? vec4( float(polyEnableFog), 0.0, 0.0, float((newFragColor.a > 0.999) ? 1.0 : 0.5) ) : vec4(0.0, 0.0, 0.0, 0.0);\n\ #endif\n\ #if DRAW_MODE_OPAQUE\n\ - gl_FragData[ATTACHMENT_WORKING_BUFFER] = vec4(float(!gl_FrontFacing), 0.0, 0.0, 1.0);\n\ + gl_FragData[ATTACHMENT_WORKING_BUFFER] = vec4(float(polyIsBackFacing), 0.0, 0.0, 1.0);\n\ #endif\n\ \n\ #if USE_NDS_DEPTH_CALCULATION || ENABLE_FOG\n\ @@ -1796,7 +1797,7 @@ size_t OpenGLRenderer::DrawPolygonsForIndexRange(const POLY *rawPolyList, const if (lastPolyAttr.value != rawPoly.attribute.value) { lastPolyAttr = rawPoly.attribute; - this->SetupPolygon(rawPoly, (DRAWMODE != OGLPolyDrawMode_DrawOpaquePolys), (DRAWMODE != OGLPolyDrawMode_ZeroAlphaPass)); + this->SetupPolygon(rawPoly, (DRAWMODE != OGLPolyDrawMode_DrawOpaquePolys), (DRAWMODE != OGLPolyDrawMode_ZeroAlphaPass), clippedPoly.isPolyBackFacing); } // Set up the texture if it changed @@ -2350,7 +2351,13 @@ OpenGLRenderer_1_2::~OpenGLRenderer_1_2() _pixelReadNeedsFinish = false; - delete[] ref->color4fBuffer; + free_aligned(ref->position4fBuffer); + ref->position4fBuffer = NULL; + + free_aligned(ref->texCoord2fBuffer); + ref->texCoord2fBuffer = NULL; + + free_aligned(ref->color4fBuffer); ref->color4fBuffer = NULL; if (this->isShaderSupported) @@ -2439,14 +2446,6 @@ Render3DError OpenGLRenderer_1_2::InitExtensions() } } - this->isVAOSupported = this->isVBOSupported && - (this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_vertex_array_object") || - this->IsExtensionPresent(&oglExtensionSet, "GL_APPLE_vertex_array_object")); - if (this->isVAOSupported) - { - this->CreateVAOs(); - } - this->isPBOSupported = this->isVBOSupported && (this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_pixel_buffer_object") || this->IsExtensionPresent(&oglExtensionSet, "GL_EXT_pixel_buffer_object")); @@ -2604,6 +2603,20 @@ Render3DError OpenGLRenderer_1_2::InitExtensions() { return error; } + + // If shaders aren't available, we need to take care of the vertex data format + // conversion on the CPU instead of on the GPU using these client-side buffers. + OGLRef.position4fBuffer = (GLfloat *)malloc_alignedPage(VERTLIST_SIZE * sizeof(GLfloat) * 4); + OGLRef.texCoord2fBuffer = (GLfloat *)malloc_alignedPage(VERTLIST_SIZE * sizeof(GLfloat) * 2); + OGLRef.color4fBuffer = (GLfloat *)malloc_alignedPage(VERTLIST_SIZE * sizeof(GLfloat) * 4); + } + + this->isVAOSupported = this->isVBOSupported && + (this->IsExtensionPresent(&oglExtensionSet, "GL_ARB_vertex_array_object") || + this->IsExtensionPresent(&oglExtensionSet, "GL_APPLE_vertex_array_object")); + if (this->isVAOSupported) + { + this->CreateVAOs(); } // Set rendering support flags based on driver features. @@ -2613,8 +2626,7 @@ Render3DError OpenGLRenderer_1_2::InitExtensions() this->_deviceInfo.isFogSupported = this->isShaderSupported && this->isVBOSupported && this->isFBOSupported; this->_deviceInfo.isTextureSmoothingSupported = this->isShaderSupported; - // We're requiring OpenGL v2.1 for this feature because it relies on gl_FrontFacing, which may not be supported on v2.0 drivers. - this->_isDepthLEqualPolygonFacingSupported = this->IsVersionSupported(2, 1, 0) && this->isShaderSupported && this->isVBOSupported && this->isFBOSupported; + this->_isDepthLEqualPolygonFacingSupported = this->isShaderSupported && this->isVBOSupported && this->isFBOSupported; this->_enableMultisampledRendering = ((this->_selectedMultisampleSize >= 2) && this->isMultisampledFBOSupported); @@ -2632,7 +2644,7 @@ Render3DError OpenGLRenderer_1_2::CreateVBOs() glGenBuffersARB(1, &OGLRef.vboPostprocessVtxID); glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID); - glBufferDataARB(GL_ARRAY_BUFFER_ARB, VERTLIST_SIZE * sizeof(VERT), NULL, GL_STREAM_DRAW_ARB); + glBufferDataARB(GL_ARRAY_BUFFER_ARB, VERTLIST_SIZE * sizeof(NDSVertex), NULL, GL_STREAM_DRAW_ARB); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboGeometryIndexID); glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, sizeof(OGLRef.vertIndexBuffer), NULL, GL_STREAM_DRAW_ARB); @@ -2703,25 +2715,48 @@ Render3DError OpenGLRenderer_1_2::CreateVAOs() glGenVertexArrays(1, &OGLRef.vaoPostprocessStatesID); glBindVertexArray(OGLRef.vaoGeometryStatesID); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboGeometryIndexID); - glEnableVertexAttribArray(OGLVertexAttributeID_Position); - glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0); - glEnableVertexAttribArray(OGLVertexAttributeID_Color); - glVertexAttribPointer(OGLVertexAttributeID_Position, 4, GL_FLOAT, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, coord)); - glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, texcoord)); - glVertexAttribPointer(OGLVertexAttributeID_Color, 3, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, color)); + if (this->isShaderSupported) + { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID); + + glEnableVertexAttribArray(OGLVertexAttributeID_Position); + glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0); + glEnableVertexAttribArray(OGLVertexAttributeID_Color); + glVertexAttribPointer(OGLVertexAttributeID_Position, 4, GL_INT, GL_FALSE, sizeof(NDSVertex), (const GLvoid *)offsetof(NDSVertex, position)); + glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_INT, GL_FALSE, sizeof(NDSVertex), (const GLvoid *)offsetof(NDSVertex, texCoord)); + glVertexAttribPointer(OGLVertexAttributeID_Color, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(NDSVertex), (const GLvoid *)offsetof(NDSVertex, color)); + } + else + { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_COLOR_ARRAY); + glVertexPointer(4, GL_FLOAT, 0, OGLRef.position4fBuffer); + glTexCoordPointer(2, GL_FLOAT, 0, OGLRef.texCoord2fBuffer); + glColorPointer(4, GL_FLOAT, 0, OGLRef.color4fBuffer); + } glBindVertexArray(0); glBindVertexArray(OGLRef.vaoPostprocessStatesID); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboPostprocessVtxID); - glEnableVertexAttribArray(OGLVertexAttributeID_Position); - glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0); - glVertexAttribPointer(OGLVertexAttributeID_Position, 2, GL_FLOAT, GL_FALSE, 0, 0); - glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)(sizeof(GLfloat) * 8)); + if (this->isShaderSupported) + { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboPostprocessVtxID); + + glEnableVertexAttribArray(OGLVertexAttributeID_Position); + glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0); + glVertexAttribPointer(OGLVertexAttributeID_Position, 2, GL_FLOAT, GL_FALSE, 0, 0); + glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid *)(sizeof(GLfloat) * 8)); + } + else + { + // Do nothing. Framebuffer post-processing requires shaders. + } glBindVertexArray(0); @@ -2822,6 +2857,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() // Set up FBOs glGenFramebuffersEXT(1, &OGLRef.fboClearImageID); + glGenFramebuffersEXT(1, &OGLRef.fboFramebufferFlipID); glGenFramebuffersEXT(1, &OGLRef.fboRenderID); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboClearImageID); @@ -2838,6 +2874,18 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() return OGLERROR_FBO_CREATE_ERROR; } + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboFramebufferFlipID); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGColorID, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_WORKING_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texFinalColorID, 0); + + if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) + { + INFO("OpenGL: Failed to create FBOs!\n"); + this->DestroyFBOs(); + + return OGLERROR_FBO_CREATE_ERROR; + } + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOROUT_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGColorID, 0); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_POLYID_ATTACHMENT_ID, GL_TEXTURE_2D, OGLRef.texGPolyID, 0); @@ -2874,6 +2922,7 @@ void OpenGLRenderer_1_2::DestroyFBOs() glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); glDeleteFramebuffersEXT(1, &OGLRef.fboClearImageID); + glDeleteFramebuffersEXT(1, &OGLRef.fboFramebufferFlipID); glDeleteFramebuffersEXT(1, &OGLRef.fboRenderID); glDeleteTextures(1, &OGLRef.texCIColorID); glDeleteTextures(1, &OGLRef.texCIFogAttrID); @@ -2884,6 +2933,7 @@ void OpenGLRenderer_1_2::DestroyFBOs() glDeleteTextures(1, &OGLRef.texGDepthStencilID); OGLRef.fboClearImageID = 0; + OGLRef.fboFramebufferFlipID = 0; OGLRef.fboRenderID = 0; this->isFBOSupported = false; @@ -3049,7 +3099,7 @@ Render3DError OpenGLRenderer_1_2::CreateGeometryPrograms() std::stringstream shaderFlags; shaderFlags << "#define USE_TEXTURE_SMOOTHING " << ((this->_enableTextureSmoothing) ? 1 : 0) << "\n"; shaderFlags << "#define USE_NDS_DEPTH_CALCULATION " << ((this->_emulateNDSDepthCalculation) ? 1 : 0) << "\n"; - shaderFlags << "#define USE_DEPTH_LEQUAL_POLYGON_FACING " << ((this->_emulateDepthLEqualPolygonFacing && this->IsVersionSupported(2, 1, 0) && this->isVBOSupported && this->isFBOSupported) ? 1 : 0) << "\n"; + shaderFlags << "#define USE_DEPTH_LEQUAL_POLYGON_FACING " << ((this->_emulateDepthLEqualPolygonFacing && this->isVBOSupported && this->isFBOSupported) ? 1 : 0) << "\n"; shaderFlags << "\n"; shaderFlags << "#define ENABLE_W_DEPTH " << ((programFlags.EnableWDepth) ? 1 : 0) << "\n"; shaderFlags << "#define ENABLE_ALPHA_TEST " << ((programFlags.EnableAlphaTest) ? "true\n" : "false\n"); @@ -3057,7 +3107,7 @@ Render3DError OpenGLRenderer_1_2::CreateGeometryPrograms() shaderFlags << "#define TOON_SHADING_MODE " << ((programFlags.ToonShadingMode) ? 1 : 0) << "\n"; shaderFlags << "#define ENABLE_FOG " << ((programFlags.EnableFog && this->isVBOSupported && this->isFBOSupported) ? 1 : 0) << "\n"; shaderFlags << "#define ENABLE_EDGE_MARK " << ((programFlags.EnableEdgeMark && this->isVBOSupported && this->isFBOSupported) ? 1 : 0) << "\n"; - shaderFlags << "#define DRAW_MODE_OPAQUE " << ((programFlags.OpaqueDrawMode && this->IsVersionSupported(2, 1, 0) && this->isVBOSupported && this->isFBOSupported) ? 1 : 0) << "\n"; + shaderFlags << "#define DRAW_MODE_OPAQUE " << ((programFlags.OpaqueDrawMode && this->isVBOSupported && this->isFBOSupported) ? 1 : 0) << "\n"; shaderFlags << "\n"; shaderFlags << "#define ATTACHMENT_WORKING_BUFFER " << GeometryAttachmentWorkingBuffer[programFlags.DrawBuffersMode] << "\n"; shaderFlags << "#define ATTACHMENT_POLY_ID " << GeometryAttachmentPolyID[programFlags.DrawBuffersMode] << "\n"; @@ -3103,7 +3153,7 @@ Render3DError OpenGLRenderer_1_2::CreateGeometryPrograms() if (this->_emulateDepthLEqualPolygonFacing && this->_isDepthLEqualPolygonFacingSupported && !programFlags.OpaqueDrawMode) { - const GLint uniformTexBackfacing = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "inBackFacing"); + const GLint uniformTexBackfacing = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "inDstBackFacing"); glUniform1i(uniformTexBackfacing, OGLTextureUnitID_FinalColor); } @@ -3122,6 +3172,7 @@ Render3DError OpenGLRenderer_1_2::CreateGeometryPrograms() OGLRef.uniformTexDrawOpaque[flagsValue] = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "texDrawOpaque"); OGLRef.uniformDrawModeDepthEqualsTest[flagsValue] = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "drawModeDepthEqualsTest"); + OGLRef.uniformPolyIsBackFacing[flagsValue] = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "polyIsBackFacing"); OGLRef.uniformPolyDrawShadow[flagsValue] = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "polyDrawShadow"); OGLRef.uniformPolyDepthOffset[flagsValue] = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "polyDepthOffset"); } @@ -3658,12 +3709,6 @@ Render3DError OpenGLRenderer_1_2::InitFinalRenderStates(const std::setisShaderSupported) ? NULL : new GLfloat[VERTLIST_SIZE * 4]; - return OGLERROR_NOERR; } @@ -3828,29 +3873,18 @@ Render3DError OpenGLRenderer_1_2::EnableVertexAttributes() glEnableVertexAttribArray(OGLVertexAttributeID_Position); glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0); glEnableVertexAttribArray(OGLVertexAttributeID_Color); - glVertexAttribPointer(OGLVertexAttributeID_Position, 4, GL_FLOAT, GL_FALSE, sizeof(VERT), OGLRef.vtxPtrPosition); - glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(VERT), OGLRef.vtxPtrTexCoord); - glVertexAttribPointer(OGLVertexAttributeID_Color, 3, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(VERT), OGLRef.vtxPtrColor); + glVertexAttribPointer(OGLVertexAttributeID_Position, 4, GL_INT, GL_FALSE, sizeof(NDSVertex), (const GLvoid *)offsetof(NDSVertex, position)); + glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_INT, GL_FALSE, sizeof(NDSVertex), (const GLvoid *)offsetof(NDSVertex, texCoord)); + glVertexAttribPointer(OGLVertexAttributeID_Color, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(NDSVertex), (const GLvoid *)offsetof(NDSVertex, color)); } else { + glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_COLOR_ARRAY); - glEnableClientState(GL_VERTEX_ARRAY); - - if (this->isVBOSupported) - { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); - glColorPointer(4, GL_FLOAT, 0, OGLRef.vtxPtrColor); - glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID); - } - else - { - glColorPointer(4, GL_FLOAT, 0, OGLRef.vtxPtrColor); - } - - glVertexPointer(4, GL_FLOAT, sizeof(VERT), OGLRef.vtxPtrPosition); - glTexCoordPointer(2, GL_FLOAT, sizeof(VERT), OGLRef.vtxPtrTexCoord); + glVertexPointer(4, GL_FLOAT, 0, OGLRef.position4fBuffer); + glTexCoordPointer(2, GL_FLOAT, 0, OGLRef.texCoord2fBuffer); + glColorPointer(4, GL_FLOAT, 0, OGLRef.color4fBuffer); } } @@ -3874,8 +3908,8 @@ Render3DError OpenGLRenderer_1_2::DisableVertexAttributes() else { glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); } } @@ -4130,20 +4164,16 @@ Render3DError OpenGLRenderer_1_2::ReadBackPixels() { // Just flips the framebuffer in Y to match the coordinates of OpenGL and the NDS hardware. // Further colorspace conversion will need to be done in a later step. - if (this->_lastTextureDrawTarget == OGLTextureUnitID_GColor) - { - glDrawBuffer(GL_WORKING_ATTACHMENT_ID); - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); - glBlitFramebufferEXT(0, (GLint)this->_framebufferHeight, (GLint)this->_framebufferWidth, 0, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); - glReadBuffer(GL_WORKING_ATTACHMENT_ID); - } - else - { - glDrawBuffer(GL_COLOROUT_ATTACHMENT_ID); - glReadBuffer(GL_WORKING_ATTACHMENT_ID); - glBlitFramebufferEXT(0, (GLint)this->_framebufferHeight, (GLint)this->_framebufferWidth, 0, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); - glReadBuffer(GL_COLOROUT_ATTACHMENT_ID); - } + + const GLenum flipTarget = (this->_lastTextureDrawTarget == OGLTextureUnitID_GColor) ? GL_WORKING_ATTACHMENT_ID : GL_COLOROUT_ATTACHMENT_ID; + + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboFramebufferFlipID); + glDrawBuffer(flipTarget); + + glBlitFramebufferEXT(0, (GLint)this->_framebufferHeight, (GLint)this->_framebufferWidth, 0, 0, 0, (GLint)this->_framebufferWidth, (GLint)this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboFramebufferFlipID); + glReadBuffer(flipTarget); } if (this->isPBOSupported) @@ -4181,18 +4211,18 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State &renderState, co if (this->isVBOSupported) { - glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, OGLRef.iboGeometryIndexID); - // Only copy as much vertex data as we need to, since this can be a potentially large upload size. - glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(VERT) * renderGList.rawVertCount, renderGList.rawVertList); - } - else - { - // If VBOs aren't supported, we need to use the client-side buffers here. - OGLRef.vtxPtrPosition = (GLvoid *)&renderGList.rawVertList[0].coord; - OGLRef.vtxPtrTexCoord = (GLvoid *)&renderGList.rawVertList[0].texcoord; - OGLRef.vtxPtrColor = (this->isShaderSupported) ? (GLvoid *)&renderGList.rawVertList[0].color : OGLRef.color4fBuffer; + if (this->isShaderSupported) + { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, OGLRef.vboGeometryVtxID); + glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(NDSVertex) * renderGList.rawVertCount, renderGList.rawVtxList); + } + else + { + // If shaders aren't supported, we need to use the client-side buffers here. + glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); + } } // Generate the clipped polygon list. @@ -4234,27 +4264,38 @@ Render3DError OpenGLRenderer_1_2::BeginRender(const GFX3D_State &renderState, co for (size_t j = 0; j < polyType; j++) { - const GLushort vertIndex = rawPoly.vertIndexes[j]; - const size_t colorIndex = vertIndex * 4; + const GLushort vtxIndex = rawPoly.vertIndexes[j]; + const size_t positionIndex = vtxIndex * 4; + const size_t texCoordIndex = vtxIndex * 2; + const size_t colorIndex = vtxIndex * 4; + const NDSVertex &vtx = renderGList.rawVtxList[vtxIndex]; - // Consolidate the vertex color and the poly alpha to our internal color buffer - // so that OpenGL can use it. - const VERT *vertForAlpha = &renderGList.rawVertList[vertIndex]; - OGLRef.color4fBuffer[colorIndex+0] = divide6bitBy63_LUT[vertForAlpha->color[0]]; - OGLRef.color4fBuffer[colorIndex+1] = divide6bitBy63_LUT[vertForAlpha->color[1]]; - OGLRef.color4fBuffer[colorIndex+2] = divide6bitBy63_LUT[vertForAlpha->color[2]]; + // Since we can't use shaders, we can't perform any data format conversions + // of the vertex data on the GPU. Therefore, we need to do the conversions + // on the CPU instead. + OGLRef.position4fBuffer[positionIndex+0] = (float)vtx.position.x / 4096.0f; + OGLRef.position4fBuffer[positionIndex+1] = (float)vtx.position.y / 4096.0f; + OGLRef.position4fBuffer[positionIndex+2] = (float)vtx.position.z / 4096.0f; + OGLRef.position4fBuffer[positionIndex+3] = (float)vtx.position.w / 4096.0f; + + OGLRef.texCoord2fBuffer[texCoordIndex+0] = (float)vtx.texCoord.s / 16.0f; + OGLRef.texCoord2fBuffer[texCoordIndex+1] = (float)vtx.texCoord.t / 16.0f; + + OGLRef.color4fBuffer[colorIndex+0] = divide6bitBy63_LUT[vtx.color.r]; + OGLRef.color4fBuffer[colorIndex+1] = divide6bitBy63_LUT[vtx.color.g]; + OGLRef.color4fBuffer[colorIndex+2] = divide6bitBy63_LUT[vtx.color.b]; OGLRef.color4fBuffer[colorIndex+3] = thePolyAlpha; // While we're looping through our vertices, add each vertex index to a // buffer. For GFX3D_QUADS and GFX3D_QUAD_STRIP, we also add additional // vertices here to convert them to GL_TRIANGLES, which are much easier // to work with and won't be deprecated in future OpenGL versions. - OGLRef.vertIndexBuffer[vertIndexCount++] = vertIndex; + OGLRef.vertIndexBuffer[vertIndexCount++] = vtxIndex; if (!GFX3D_IsPolyWireframe(rawPoly) && (rawPoly.vtxFormat == GFX3D_QUADS || rawPoly.vtxFormat == GFX3D_QUAD_STRIP)) { if (j == 2) { - OGLRef.vertIndexBuffer[vertIndexCount++] = vertIndex; + OGLRef.vertIndexBuffer[vertIndexCount++] = vtxIndex; } else if (j == 3) { @@ -4396,13 +4437,14 @@ Render3DError OpenGLRenderer_1_2::RenderGeometry() size_t indexOffset = 0; + const CPoly &firstCPoly = this->_clippedPolyList[0]; const POLY *rawPolyList = this->_rawPolyList; - const POLY &firstPoly = rawPolyList[this->_clippedPolyList[0].index]; + const POLY &firstPoly = rawPolyList[firstCPoly.index]; POLYGON_ATTR lastPolyAttr = firstPoly.attribute; if (this->_clippedPolyOpaqueCount > 0) { - this->SetupPolygon(firstPoly, false, true); + this->SetupPolygon(firstPoly, false, true, firstCPoly.isPolyBackFacing); this->DrawPolygonsForIndexRange(rawPolyList, this->_clippedPolyList, this->_clippedPolyCount, 0, this->_clippedPolyOpaqueCount - 1, indexOffset, lastPolyAttr); } @@ -4414,16 +4456,17 @@ Render3DError OpenGLRenderer_1_2::RenderGeometry() { if (this->_clippedPolyOpaqueCount == 0) { - this->SetupPolygon(firstPoly, true, false); + this->SetupPolygon(firstPoly, true, false, firstCPoly.isPolyBackFacing); } this->ZeroDstAlphaPass(rawPolyList, this->_clippedPolyList, this->_clippedPolyCount, this->_clippedPolyOpaqueCount, this->_enableAlphaBlending, indexOffset, lastPolyAttr); if (this->_clippedPolyOpaqueCount > 0) { - const POLY &lastOpaquePoly = rawPolyList[this->_clippedPolyList[this->_clippedPolyOpaqueCount - 1].index]; + const CPoly &lastOpaqueCPoly = this->_clippedPolyList[this->_clippedPolyOpaqueCount - 1]; + const POLY &lastOpaquePoly = rawPolyList[lastOpaqueCPoly.index]; lastPolyAttr = lastOpaquePoly.attribute; - this->SetupPolygon(lastOpaquePoly, false, true); + this->SetupPolygon(lastOpaquePoly, false, true, lastOpaqueCPoly.isPolyBackFacing); } } else @@ -4440,7 +4483,7 @@ Render3DError OpenGLRenderer_1_2::RenderGeometry() if (this->_clippedPolyOpaqueCount == 0) { - this->SetupPolygon(firstPoly, true, true); + this->SetupPolygon(firstPoly, true, true, firstCPoly.isPolyBackFacing); } else { @@ -4781,7 +4824,7 @@ void OpenGLRenderer_1_2::SetPolygonIndex(const size_t index) this->_currentPolyIndex = index; } -Render3DError OpenGLRenderer_1_2::SetupPolygon(const POLY &thePoly, bool treatAsTranslucent, bool willChangeStencilBuffer) +Render3DError OpenGLRenderer_1_2::SetupPolygon(const POLY &thePoly, bool treatAsTranslucent, bool willChangeStencilBuffer, bool isBackFacing) { // Set up depth test mode glDepthFunc((thePoly.attribute.DepthEqualTest_Enable) ? GL_EQUAL : GL_LESS); @@ -4860,6 +4903,7 @@ Render3DError OpenGLRenderer_1_2::SetupPolygon(const POLY &thePoly, bool treatAs glUniform1i(OGLRef.uniformPolyIsWireframe[this->_geometryProgramFlags.value], (GFX3D_IsPolyWireframe(thePoly)) ? GL_TRUE : GL_FALSE); glUniform1i(OGLRef.uniformPolySetNewDepthForTranslucent[this->_geometryProgramFlags.value], (thePoly.attribute.TranslucentDepthWrite_Enable) ? GL_TRUE : GL_FALSE); glUniform1f(OGLRef.uniformPolyDepthOffset[this->_geometryProgramFlags.value], 0.0f); + glUniform1i(OGLRef.uniformPolyIsBackFacing[this->_geometryProgramFlags.value], (isBackFacing) ? GL_TRUE : GL_FALSE); } else { @@ -5119,6 +5163,16 @@ Render3DError OpenGLRenderer_1_2::Reset() this->_pixelReadNeedsFinish = false; + if (OGLRef.position4fBuffer != NULL) + { + memset(OGLRef.position4fBuffer, 0, VERTLIST_SIZE * 4 * sizeof(GLfloat)); + } + + if (OGLRef.texCoord2fBuffer != NULL) + { + memset(OGLRef.texCoord2fBuffer, 0, VERTLIST_SIZE * 2 * sizeof(GLfloat)); + } + if (OGLRef.color4fBuffer != NULL) { memset(OGLRef.color4fBuffer, 0, VERTLIST_SIZE * 4 * sizeof(GLfloat)); @@ -5126,10 +5180,6 @@ Render3DError OpenGLRenderer_1_2::Reset() this->_currentPolyIndex = 0; - OGLRef.vtxPtrPosition = (GLvoid *)offsetof(VERT, coord); - OGLRef.vtxPtrTexCoord = (GLvoid *)offsetof(VERT, texcoord); - OGLRef.vtxPtrColor = (this->isShaderSupported) ? (GLvoid *)offsetof(VERT, color) : OGLRef.color4fBuffer; - memset(&this->_pendingRenderStates, 0, sizeof(this->_pendingRenderStates)); texCache.Reset(); @@ -5371,6 +5421,8 @@ Render3DError OpenGLRenderer_2_0::InitFinalRenderStates(const std::set> 15) & 0x01;\n\ polyEnableTexture = (polyStateBits >> 16) & 0x01;\n\ texSingleBitAlpha = (polyStateBits >> 17) & 0x01;\n\ + polyIsBackFacing = (polyStateBits >> 24) & 0x01;\n\ \n\ isPolyDrawable = int((polyMode != 3) || polyDrawShadow);\n\ \n\ mat2 texScaleMtx = mat2( vec2(polyTexScale.x, 0.0), \n\ vec2( 0.0, polyTexScale.y)); \n\ \n\ - vtxTexCoord = texScaleMtx * inTexCoord0;\n\ + vtxTexCoord = (texScaleMtx * inTexCoord0) / 16.0;\n\ vtxColor = vec4(inColor / 63.0, polyAlpha);\n\ - gl_Position = inPosition;\n\ + gl_Position = inPosition / 4096.0;\n\ }\n\ "}; @@ -188,6 +190,7 @@ flat in int polySetNewDepthForTranslucent;\n\ flat in int polyMode;\n\ flat in int polyID;\n\ flat in int texSingleBitAlpha;\n\ +flat in int polyIsBackFacing;\n\ flat in int isPolyDrawable;\n\ \n\ layout (std140) uniform RenderStates\n\ @@ -212,9 +215,9 @@ uniform bool polyDrawShadow;\n\ uniform float polyDepthOffset;\n\ \n\ #if DRAW_MODE_OPAQUE\n\ -out vec4 outBackFacing;\n\ +out vec4 outDstBackFacing;\n\ #elif USE_DEPTH_LEQUAL_POLYGON_FACING\n\ -uniform sampler2D inBackFacing;\n\ +uniform sampler2D inDstBackFacing;\n\ #endif\n\ \n\ out vec4 outFragColor;\n\ @@ -232,8 +235,8 @@ layout (depth_less) out float gl_FragDepth;\n\ void main()\n\ {\n\ #if USE_DEPTH_LEQUAL_POLYGON_FACING && !DRAW_MODE_OPAQUE\n\ - bool isOpaqueDstBackFacing = bool( texelFetch(inBackFacing, ivec2(gl_FragCoord.xy), 0).r );\n\ - if ( drawModeDepthEqualsTest && (!gl_FrontFacing || !isOpaqueDstBackFacing) )\n\ + bool isOpaqueDstBackFacing = bool( texelFetch(inDstBackFacing, ivec2(gl_FragCoord.xy), 0).r );\n\ + if ( drawModeDepthEqualsTest && (bool(polyIsBackFacing) || !isOpaqueDstBackFacing) )\n\ {\n\ discard;\n\ }\n\ @@ -305,7 +308,7 @@ void main()\n\ outFogAttributes = (isPolyDrawable != 0) ? vec4( float(polyEnableFog), 0.0, 0.0, float((outFragColor.a > 0.999) ? 1.0 : 0.5) ) : vec4(0.0, 0.0, 0.0, 0.0);\n\ #endif\n\ #if DRAW_MODE_OPAQUE\n\ - outBackFacing = vec4(float(!gl_FrontFacing), 0.0, 0.0, 1.0);\n\ + outDstBackFacing = vec4(float(polyIsBackFacing), 0.0, 0.0, 1.0);\n\ #endif\n\ \n\ #if USE_NDS_DEPTH_CALCULATION || ENABLE_FOG\n\ @@ -791,7 +794,7 @@ Render3DError OpenGLRenderer_3_2::InitExtensions() INFO("OpenGL: Driver does not support at least 2x multisampled FBOs.\n"); } - this->_isDepthLEqualPolygonFacingSupported = this->isShaderSupported && this->isVBOSupported && this->isFBOSupported; + this->_isDepthLEqualPolygonFacingSupported = true; this->_enableMultisampledRendering = ((this->_selectedMultisampleSize >= 2) && this->isMultisampledFBOSupported); this->InitFinalRenderStates(&oglExtensionSet); // This must be done last @@ -1111,9 +1114,9 @@ Render3DError OpenGLRenderer_3_2::CreateVAOs() glEnableVertexAttribArray(OGLVertexAttributeID_Position); glEnableVertexAttribArray(OGLVertexAttributeID_TexCoord0); glEnableVertexAttribArray(OGLVertexAttributeID_Color); - glVertexAttribPointer(OGLVertexAttributeID_Position, 4, GL_FLOAT, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, coord)); - glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, texcoord)); - glVertexAttribPointer(OGLVertexAttributeID_Color, 3, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(VERT), (const GLvoid *)offsetof(VERT, color)); + glVertexAttribPointer(OGLVertexAttributeID_Position, 4, GL_INT, GL_FALSE, sizeof(NDSVertex), (const GLvoid *)offsetof(NDSVertex, position)); + glVertexAttribPointer(OGLVertexAttributeID_TexCoord0, 2, GL_INT, GL_FALSE, sizeof(NDSVertex), (const GLvoid *)offsetof(NDSVertex, texCoord)); + glVertexAttribPointer(OGLVertexAttributeID_Color, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(NDSVertex), (const GLvoid *)offsetof(NDSVertex, color)); glBindVertexArray(0); @@ -1280,7 +1283,7 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms() if (programFlags.OpaqueDrawMode) { - glBindFragDataLocation(OGLRef.programGeometryID[flagsValue], GeometryAttachmentWorkingBuffer[programFlags.DrawBuffersMode], "outBackFacing"); + glBindFragDataLocation(OGLRef.programGeometryID[flagsValue], GeometryAttachmentWorkingBuffer[programFlags.DrawBuffersMode], "outDstBackFacing"); } glLinkProgram(OGLRef.programGeometryID[flagsValue]); @@ -1319,7 +1322,7 @@ Render3DError OpenGLRenderer_3_2::CreateGeometryPrograms() if (this->_emulateDepthLEqualPolygonFacing && !programFlags.OpaqueDrawMode) { - const GLint uniformTexBackfacing = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "inBackFacing"); + const GLint uniformTexBackfacing = glGetUniformLocation(OGLRef.programGeometryID[flagsValue], "inDstBackFacing"); glUniform1i(uniformTexBackfacing, OGLTextureUnitID_FinalColor); } @@ -1999,9 +2002,9 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D_State &renderState, co glDeleteSync(this->_syncBufferSetup); } - const size_t vtxBufferSize = sizeof(VERT) * renderGList.rawVertCount; - VERT *vtxPtr = (VERT *)glMapBufferRange(GL_ARRAY_BUFFER, 0, vtxBufferSize, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); - memcpy(vtxPtr, renderGList.rawVertList, vtxBufferSize); + const size_t vtxBufferSize = sizeof(NDSVertex) * renderGList.rawVertCount; + NDSVertex *vtxPtr = (NDSVertex *)glMapBufferRange(GL_ARRAY_BUFFER, 0, vtxBufferSize, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_UNSYNCHRONIZED_BIT); + memcpy(vtxPtr, renderGList.rawVtxList, vtxBufferSize); glUnmapBuffer(GL_ARRAY_BUFFER); this->_syncBufferSetup = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); @@ -2143,6 +2146,8 @@ Render3DError OpenGLRenderer_3_2::BeginRender(const GFX3D_State &renderState, co polyStates[i].TexSingleBitAlpha = (packFormat != TEXMODE_A3I5 && packFormat != TEXMODE_A5I3) ? 1 : 0; polyStates[i].TexSizeShiftS = rawPoly.texParam.SizeShiftS; // Note that we are using the preshifted size of S polyStates[i].TexSizeShiftT = rawPoly.texParam.SizeShiftT; // Note that we are using the preshifted size of T + + polyStates[i].IsBackFacing = (this->_clippedPolyList[i].isPolyBackFacing) ? 1 : 0; } if (OGLRef.uboPolyStatesID != 0) @@ -2401,7 +2406,7 @@ void OpenGLRenderer_3_2::SetPolygonIndex(const size_t index) } } -Render3DError OpenGLRenderer_3_2::SetupPolygon(const POLY &thePoly, bool treatAsTranslucent, bool willChangeStencilBuffer) +Render3DError OpenGLRenderer_3_2::SetupPolygon(const POLY &thePoly, bool treatAsTranslucent, bool willChangeStencilBuffer, bool isBackFacing) { OGLRenderRef &OGLRef = *this->ref; diff --git a/desmume/src/OGLRender_3_2.h b/desmume/src/OGLRender_3_2.h index af40f69b3..85aa39cd4 100644 --- a/desmume/src/OGLRender_3_2.h +++ b/desmume/src/OGLRender_3_2.h @@ -109,7 +109,7 @@ protected: virtual Render3DError ClearUsingValues(const FragmentColor &clearColor6665, const FragmentAttributes &clearAttributes); virtual void SetPolygonIndex(const size_t index); - virtual Render3DError SetupPolygon(const POLY &thePoly, bool treatAsTranslucent, bool willChangeStencilBuffer); + virtual Render3DError SetupPolygon(const POLY &thePoly, bool treatAsTranslucent, bool willChangeStencilBuffer, bool isBackFacing); virtual Render3DError SetupTexture(const POLY &thePoly, size_t polyRenderIndex); virtual Render3DError SetFramebufferSize(size_t w, size_t h);