diff --git a/desmume/src/GPU.cpp b/desmume/src/GPU.cpp index 435b11ef9..02843877d 100644 --- a/desmume/src/GPU.cpp +++ b/desmume/src/GPU.cpp @@ -564,12 +564,9 @@ FORCEINLINE FASTCALL void GPU::_master_setFinal3dColor(int dstX, int srcX) { int x = dstX; int passing = dstX<<1; - u8* color = &_3dColorLine[srcX<<2]; - u8 red = color[0]; - u8 green = color[1]; - u8 blue = color[2]; - u8 alpha = color[3]; - u8* dst = currDst; + const FragmentColor color = _3dColorLine[srcX]; + u8 alpha = color.a; + u8 *dst = currDst; u16 final; bool windowEffect = blend1; //bomberman land touch dialogbox will fail without setting to blend1 @@ -596,17 +593,17 @@ FORCEINLINE FASTCALL void GPU::_master_setFinal3dColor(int dstX, int srcX) c2.val = HostReadWord(dst, passing); - cfinal.bits.red = ((red * alpha) + ((c2.bits.red<<1) * (32 - alpha)))>>6; - cfinal.bits.green = ((green * alpha) + ((c2.bits.green<<1) * (32 - alpha)))>>6; - cfinal.bits.blue = ((blue * alpha) + ((c2.bits.blue<<1) * (32 - alpha)))>>6; + cfinal.bits.red = ((color.r * alpha) + ((c2.bits.red<<1) * (32 - alpha)))>>6; + cfinal.bits.green = ((color.g * alpha) + ((c2.bits.green<<1) * (32 - alpha)))>>6; + cfinal.bits.blue = ((color.b * alpha) + ((c2.bits.blue<<1) * (32 - alpha)))>>6; final = cfinal.val; } - else final = R6G6B6TORGB15(red,green,blue); + else final = R6G6B6TORGB15(color.r, color.g, color.b); } else { - final = R6G6B6TORGB15(red,green,blue); + final = R6G6B6TORGB15(color.r, color.g, color.b); //perform the special effect if(windowEffect) switch(FUNC) { @@ -2068,7 +2065,7 @@ PLAIN_CLEAR: // render BGs if (BG_enabled) { - for (int i=0; i < item->nbBGs; i++) + for (size_t i = 0; i < item->nbBGs; i++) { i16 = item->BGs[i]; if (gpu->LayersEnable[i16]) @@ -2088,17 +2085,16 @@ PLAIN_CLEAR: const u16 hofs = gpu->getHOFS(i16); gfx3d_GetLineData(l, &gpu->_3dColorLine); - u8* colorLine = gpu->_3dColorLine; + const FragmentColor *colorLine = gpu->_3dColorLine; - for(int k = 0; k < 256; k++) + for (size_t k = 0; k < 256; k++) { - int q = ((k + hofs) & 0x1FF); + const size_t q = ((k + hofs) & 0x1FF); - if((q < 0) || (q > 255)) + if (q > 255 || colorLine[q].a == 0) continue; - - if(colorLine[(q<<2)+3]) - gpu->setFinalColor3d(k, q); + + gpu->setFinalColor3d(k, q); } continue; diff --git a/desmume/src/GPU.h b/desmume/src/GPU.h index 6171b1e68..a8bdd61f1 100644 --- a/desmume/src/GPU.h +++ b/desmume/src/GPU.h @@ -110,6 +110,15 @@ struct _DISPCNT }; #endif +union FragmentColor +{ + u32 color; + struct + { + u8 r,g,b,a; + }; +}; + typedef union { struct _DISPCNT bits; @@ -688,7 +697,7 @@ struct GPU bool blend1; u8* currDst; - u8* _3dColorLine; + FragmentColor *_3dColorLine; static struct MosaicLookup { @@ -919,5 +928,11 @@ void gpu_SetRotateScreen(u16 angle); //#undef FORCEINLINE //#define FORCEINLINE __forceinline -#endif +inline FragmentColor MakeFragmentColor(const u8 r, const u8 g, const u8 b, const u8 a) +{ + FragmentColor ret; + ret.r = r; ret.g = g; ret.b = b; ret.a = a; + return ret; +} +#endif diff --git a/desmume/src/OGLRender.cpp b/desmume/src/OGLRender.cpp index 252ecbe6b..8a460e8cc 100644 --- a/desmume/src/OGLRender.cpp +++ b/desmume/src/OGLRender.cpp @@ -790,10 +790,6 @@ OpenGLRenderer::OpenGLRenderer() // Init OpenGL rendering states ref = new OGLRenderRef; - ref->workingDepthBuffer = (GLuint *)calloc(_framebufferWidth * _framebufferHeight, sizeof(GLuint)); - ref->workingDepthStencilBuffer = (GLuint *)calloc(_framebufferWidth * _framebufferHeight, sizeof(GLuint)); - ref->workingFogAttributesBuffer = (GLuint *)calloc(_framebufferWidth * _framebufferHeight, sizeof(GLuint)); - ref->workingPolyIDBuffer = (GLuint *)calloc(_framebufferWidth * _framebufferHeight, sizeof(GLuint)); ref->fboRenderID = 0; ref->fboMSIntermediateRenderID = 0; ref->fboPostprocessID = 0; @@ -807,10 +803,6 @@ OpenGLRenderer::OpenGLRenderer() OpenGLRenderer::~OpenGLRenderer() { // Destroy OpenGL rendering states - free(ref->workingDepthBuffer); - free(ref->workingDepthStencilBuffer); - free(ref->workingFogAttributesBuffer); - free(ref->workingPolyIDBuffer); delete ref; ref = NULL; } @@ -1337,10 +1329,16 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() OGLRenderRef &OGLRef = *this->ref; // Set up FBO render targets + glGenTextures(1, &OGLRef.texCIColorID); + glGenTextures(1, &OGLRef.texCIDepthID); + glGenTextures(1, &OGLRef.texCIFogAttrID); + glGenTextures(1, &OGLRef.texCIPolyID); + glGenTextures(1, &OGLRef.texCIDepthStencilID); + glGenTextures(1, &OGLRef.texGColorID); glGenTextures(1, &OGLRef.texGDepthID); - glGenTextures(1, &OGLRef.texGPolyID); glGenTextures(1, &OGLRef.texGFogAttrID); + glGenTextures(1, &OGLRef.texGPolyID); glGenTextures(1, &OGLRef.texGDepthStencilID); glGenTextures(1, &OGLRef.texPostprocessFogID); @@ -1385,6 +1383,7 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, OGLRef.texPostprocessFogID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -1392,12 +1391,88 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIColorID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthStencilID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL); + + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIPolyID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIFogAttrID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glBindTexture(GL_TEXTURE_2D, 0); // Set up FBOs + glGenFramebuffersEXT(1, &OGLRef.fboClearImageID); glGenFramebuffersEXT(1, &OGLRef.fboRenderID); glGenFramebuffersEXT(1, &OGLRef.fboPostprocessID); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboClearImageID); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, OGLRef.texCIColorID, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, OGLRef.texCIDepthID, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_TEXTURE_2D, OGLRef.texCIPolyID, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT3_EXT, GL_TEXTURE_2D, OGLRef.texCIFogAttrID, 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); + + if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) + { + INFO("OpenGL: Failed to created FBOs. Some emulation features will be disabled.\n"); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glDeleteFramebuffersEXT(1, &OGLRef.fboClearImageID); + glDeleteFramebuffersEXT(1, &OGLRef.fboRenderID); + glDeleteFramebuffersEXT(1, &OGLRef.fboPostprocessID); + glDeleteTextures(1, &OGLRef.texCIColorID); + glDeleteTextures(1, &OGLRef.texCIDepthID); + glDeleteTextures(1, &OGLRef.texCIFogAttrID); + glDeleteTextures(1, &OGLRef.texCIPolyID); + glDeleteTextures(1, &OGLRef.texCIDepthStencilID); + glDeleteTextures(1, &OGLRef.texGColorID); + glDeleteTextures(1, &OGLRef.texGDepthID); + glDeleteTextures(1, &OGLRef.texGPolyID); + glDeleteTextures(1, &OGLRef.texGFogAttrID); + glDeleteTextures(1, &OGLRef.texGDepthStencilID); + glDeleteTextures(1, &OGLRef.texPostprocessFogID); + + OGLRef.fboClearImageID = 0; + OGLRef.fboRenderID = 0; + OGLRef.fboPostprocessID = 0; + + this->isFBOSupported = false; + return OGLERROR_FBO_CREATE_ERROR; + } + + glDrawBuffers(4, RenderDrawList); + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID); 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.texGDepthID, 0); @@ -1411,8 +1486,14 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() INFO("OpenGL: Failed to created FBOs. Some emulation features will be disabled.\n"); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glDeleteFramebuffersEXT(1, &OGLRef.fboClearImageID); glDeleteFramebuffersEXT(1, &OGLRef.fboRenderID); glDeleteFramebuffersEXT(1, &OGLRef.fboPostprocessID); + glDeleteTextures(1, &OGLRef.texCIColorID); + glDeleteTextures(1, &OGLRef.texCIDepthID); + glDeleteTextures(1, &OGLRef.texCIFogAttrID); + glDeleteTextures(1, &OGLRef.texCIPolyID); + glDeleteTextures(1, &OGLRef.texCIDepthStencilID); glDeleteTextures(1, &OGLRef.texGColorID); glDeleteTextures(1, &OGLRef.texGDepthID); glDeleteTextures(1, &OGLRef.texGPolyID); @@ -1420,6 +1501,10 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() glDeleteTextures(1, &OGLRef.texGDepthStencilID); glDeleteTextures(1, &OGLRef.texPostprocessFogID); + OGLRef.fboClearImageID = 0; + OGLRef.fboRenderID = 0; + OGLRef.fboPostprocessID = 0; + this->isFBOSupported = false; return OGLERROR_FBO_CREATE_ERROR; } @@ -1435,8 +1520,14 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() INFO("OpenGL: Failed to created FBOs. Some emulation features will be disabled.\n"); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glDeleteFramebuffersEXT(1, &OGLRef.fboClearImageID); glDeleteFramebuffersEXT(1, &OGLRef.fboRenderID); glDeleteFramebuffersEXT(1, &OGLRef.fboPostprocessID); + glDeleteTextures(1, &OGLRef.texCIColorID); + glDeleteTextures(1, &OGLRef.texCIDepthID); + glDeleteTextures(1, &OGLRef.texCIFogAttrID); + glDeleteTextures(1, &OGLRef.texCIPolyID); + glDeleteTextures(1, &OGLRef.texCIDepthStencilID); glDeleteTextures(1, &OGLRef.texGColorID); glDeleteTextures(1, &OGLRef.texGDepthID); glDeleteTextures(1, &OGLRef.texGPolyID); @@ -1444,6 +1535,10 @@ Render3DError OpenGLRenderer_1_2::CreateFBOs() glDeleteTextures(1, &OGLRef.texGDepthStencilID); glDeleteTextures(1, &OGLRef.texPostprocessFogID); + OGLRef.fboClearImageID = 0; + OGLRef.fboRenderID = 0; + OGLRef.fboPostprocessID = 0; + this->isFBOSupported = false; return OGLERROR_FBO_CREATE_ERROR; } @@ -1468,8 +1563,14 @@ void OpenGLRenderer_1_2::DestroyFBOs() OGLRenderRef &OGLRef = *this->ref; glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + glDeleteFramebuffersEXT(1, &OGLRef.fboClearImageID); glDeleteFramebuffersEXT(1, &OGLRef.fboRenderID); glDeleteFramebuffersEXT(1, &OGLRef.fboPostprocessID); + glDeleteTextures(1, &OGLRef.texCIColorID); + glDeleteTextures(1, &OGLRef.texCIDepthID); + glDeleteTextures(1, &OGLRef.texCIFogAttrID); + glDeleteTextures(1, &OGLRef.texCIPolyID); + glDeleteTextures(1, &OGLRef.texCIDepthStencilID); glDeleteTextures(1, &OGLRef.texGColorID); glDeleteTextures(1, &OGLRef.texGDepthID); glDeleteTextures(1, &OGLRef.texGPolyID); @@ -1477,6 +1578,7 @@ void OpenGLRenderer_1_2::DestroyFBOs() glDeleteTextures(1, &OGLRef.texGDepthStencilID); glDeleteTextures(1, &OGLRef.texPostprocessFogID); + OGLRef.fboClearImageID = 0; OGLRef.fboRenderID = 0; OGLRef.fboPostprocessID = 0; @@ -1704,40 +1806,43 @@ Render3DError OpenGLRenderer_1_2::UploadClearImage(const u16 *__restrict colorBu if (this->isShaderSupported) { - for (size_t i = 0; i < this->_framebufferWidth * this->_framebufferHeight; i++) + for (size_t i = 0; i < GFX3D_FRAMEBUFFER_WIDTH * GFX3D_FRAMEBUFFER_HEIGHT; i++) { - OGLRef.workingDepthStencilBuffer[i] = depthBuffer[i] << 8; - OGLRef.workingDepthBuffer[i] = depthBuffer[i] | 0xFF000000; - OGLRef.workingFogAttributesBuffer[i] = (fogBuffer[i]) ? 0xFF0000FF : 0xFF000000; - OGLRef.workingPolyIDBuffer[i] = (GLuint)polyIDBuffer[i] | 0xFF000000; + OGLRef.workingCIDepthStencilBuffer[i] = depthBuffer[i] << 8; + OGLRef.workingCIDepthBuffer[i] = depthBuffer[i] | 0xFF000000; + OGLRef.workingCIFogAttributesBuffer[i] = (fogBuffer[i]) ? 0xFF0000FF : 0xFF000000; + OGLRef.workingCIPolyIDBuffer[i] = (GLuint)polyIDBuffer[i] | 0xFF000000; } } else { for (size_t i = 0; i < this->_framebufferWidth * this->_framebufferHeight; i++) { - OGLRef.workingDepthStencilBuffer[i] = depthBuffer[i] << 8; + OGLRef.workingCIDepthStencilBuffer[i] = depthBuffer[i] << 8; } } - glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_GColor); - glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthStencilID); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, OGLRef.workingDepthStencilBuffer); - glBindTexture(GL_TEXTURE_2D, OGLRef.texGColorID); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, colorBuffer); + glActiveTextureARB(GL_TEXTURE0_ARB); + + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIColorID); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, colorBuffer); + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthStencilID); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, OGLRef.workingCIDepthStencilBuffer); if (this->isShaderSupported) { - glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_GDepth); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingDepthBuffer); + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthID); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingCIDepthBuffer); - glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_FogAttr); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingFogAttributesBuffer); + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIFogAttrID); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingCIFogAttributesBuffer); - glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_GPolyID); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingPolyIDBuffer); + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIPolyID); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingCIPolyIDBuffer); } + glBindTexture(GL_TEXTURE_2D, 0); + return OGLERROR_NOERR; } @@ -2186,20 +2291,49 @@ Render3DError OpenGLRenderer_1_2::ClearUsingImage(const u16 *__restrict colorBuf this->UploadClearImage(colorBuffer, depthBuffer, fogBuffer, polyIDBuffer); + glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, OGLRef.fboClearImageID); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboRenderID); + + // It might seem wasteful to be doing a separate glClear(GL_STENCIL_BUFFER_BIT) instead + // of simply blitting the stencil buffer with everything else. + // + // We do this because glBlitFramebufferEXT() for GL_STENCIL_BUFFER_BIT has been tested + // to be unsupported on ATI/AMD GPUs running in compatibility mode. So we do the separate + // glClear() for GL_STENCIL_BUFFER_BIT to keep these GPUs working. + glClearStencil(0); + glClear(GL_STENCIL_BUFFER_BIT); + + // Blit the working depth buffer + glReadBuffer(GL_COLOR_ATTACHMENT1_EXT); + glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT); + glBlitFramebufferEXT(0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + // Blit the polygon ID buffer + glReadBuffer(GL_COLOR_ATTACHMENT2_EXT); + glDrawBuffer(GL_COLOR_ATTACHMENT2_EXT); + glBlitFramebufferEXT(0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + // Blit the fog buffer + glReadBuffer(GL_COLOR_ATTACHMENT3_EXT); + glDrawBuffer(GL_COLOR_ATTACHMENT3_EXT); + glBlitFramebufferEXT(0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + // Blit the color buffer. Do this last so that color attachment 0 is set to the read FBO. + glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + glBlitFramebufferEXT(0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.fboRenderID); + glDrawBuffers(4, RenderDrawList); + if (this->isMultisampledFBOSupported) { OGLRef.selectedRenderingFBO = (CommonSettings.GFX3D_Renderer_Multisample) ? OGLRef.fboMSIntermediateRenderID : OGLRef.fboRenderID; if (OGLRef.selectedRenderingFBO == OGLRef.fboMSIntermediateRenderID) { glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, OGLRef.fboRenderID); - glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.fboMSIntermediateRenderID); + glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, OGLRef.selectedRenderingFBO); - // It might seem wasteful to be doing a separate glClear(GL_STENCIL_BUFFER_BIT) instead - // of simply blitting the stencil buffer with everything else. - // - // We do this because glBlitFramebufferEXT() for GL_STENCIL_BUFFER_BIT has been tested - // to be unsupported on ATI/AMD GPUs running in compatibility mode. So we do the separate - // glClear() for GL_STENCIL_BUFFER_BIT to keep these GPUs working. glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); @@ -2222,10 +2356,10 @@ Render3DError OpenGLRenderer_1_2::ClearUsingImage(const u16 *__restrict colorBuf glReadBuffer(GL_COLOR_ATTACHMENT0_EXT); glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); glBlitFramebufferEXT(0, 0, this->_framebufferWidth, this->_framebufferHeight, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.selectedRenderingFBO); + glDrawBuffers(4, RenderDrawList); } - - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, OGLRef.selectedRenderingFBO); - glDrawBuffers(4, RenderDrawList); } return OGLERROR_NOERR; @@ -2457,9 +2591,12 @@ Render3DError OpenGLRenderer_1_2::SetupTexture(const POLY &thePoly, bool enableT Render3DError OpenGLRenderer_1_2::SetupViewport(const u32 viewportValue) { + const GLfloat wScalar = this->_framebufferWidth / GFX3D_FRAMEBUFFER_WIDTH; + const GLfloat hScalar = this->_framebufferHeight / GFX3D_FRAMEBUFFER_HEIGHT; + VIEWPORT viewport; viewport.decode(viewportValue); - glViewport(viewport.x, viewport.y, viewport.width, viewport.height); + glViewport(viewport.x * wScalar, viewport.y * hScalar, viewport.width * wScalar, viewport.height * hScalar); return OGLERROR_NOERR; } @@ -2506,8 +2643,6 @@ Render3DError OpenGLRenderer_1_2::Reset() OGLRef.vtxPtrTexCoord = (GLvoid *)offsetof(VERT, texcoord); OGLRef.vtxPtrColor = (this->isShaderSupported) ? (GLvoid *)offsetof(VERT, color) : OGLRef.color4fBuffer; - - memset(this->clearImageColor16Buffer, 0, sizeof(this->clearImageColor16Buffer)); memset(this->clearImageDepthBuffer, 0, sizeof(this->clearImageDepthBuffer)); memset(this->clearImagePolyIDBuffer, 0, sizeof(this->clearImagePolyIDBuffer)); @@ -2546,7 +2681,7 @@ Render3DError OpenGLRenderer_1_2::RenderFinish() ENDGL(); - this->FlushFramebuffer((FragmentColor *)gfx3d_convertedScreen); + this->FlushFramebuffer(gfx3d_convertedScreen); this->_pixelReadNeedsFinish = false; return OGLERROR_NOERR; @@ -2554,14 +2689,63 @@ Render3DError OpenGLRenderer_1_2::RenderFinish() Render3DError OpenGLRenderer_1_2::SetFramebufferSize(size_t w, size_t h) { + OGLRenderRef &OGLRef = *this->ref; + if (w < GFX3D_FRAMEBUFFER_WIDTH || h < GFX3D_FRAMEBUFFER_HEIGHT) { - return RENDER3DERROR_NOERR; + return OGLERROR_NOERR; } - // TODO: We're not prepared to do this yet, so do nothing for now. + this->_framebufferWidth = w; + this->_framebufferHeight = h; + this->_framebufferColorSizeBytes = w * h * sizeof(FragmentColor); + this->_framebufferColor = (FragmentColor *)realloc(this->_framebufferColor, this->_framebufferColorSizeBytes); - return RENDER3DERROR_NOERR; + if (this->isFBOSupported) + { + glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_GColor); + glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthStencilID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, w, h, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL); + glBindTexture(GL_TEXTURE_2D, OGLRef.texGColorID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_GDepth); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_GPolyID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glActiveTextureARB(GL_TEXTURE0_ARB + OGLTextureUnitID_FogAttr); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glActiveTextureARB(GL_TEXTURE0_ARB); + glBindTexture(GL_TEXTURE_2D, OGLRef.texPostprocessFogID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + } + + if (this->isMultisampledFBOSupported) + { + GLint maxSamples = 0; + glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples); + + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGColorID); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthID); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGPolyID); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGFogAttrID); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthStencilID); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_DEPTH24_STENCIL8_EXT, w, h); + } + + if (this->isPBOSupported) + { + glBufferData(GL_PIXEL_PACK_BUFFER_ARB, this->_framebufferColorSizeBytes, NULL, GL_STREAM_READ); + } + + return OGLERROR_NOERR; } Render3DError OpenGLRenderer_1_3::CreateToonTable() @@ -2600,38 +2784,102 @@ Render3DError OpenGLRenderer_1_3::UploadClearImage(const u16 *__restrict colorBu if (this->isShaderSupported) { - for (size_t i = 0; i < this->_framebufferWidth * this->_framebufferHeight; i++) + for (size_t i = 0; i < GFX3D_FRAMEBUFFER_WIDTH * GFX3D_FRAMEBUFFER_HEIGHT; i++) { - OGLRef.workingDepthStencilBuffer[i] = depthBuffer[i] << 8; - OGLRef.workingDepthBuffer[i] = depthBuffer[i] | 0xFF000000; - OGLRef.workingFogAttributesBuffer[i] = (fogBuffer[i]) ? 0xFF0000FF : 0xFF000000; - OGLRef.workingPolyIDBuffer[i] = (GLuint)polyIDBuffer[i] | 0xFF000000; + OGLRef.workingCIDepthStencilBuffer[i] = depthBuffer[i] << 8; + OGLRef.workingCIDepthBuffer[i] = depthBuffer[i] | 0xFF000000; + OGLRef.workingCIFogAttributesBuffer[i] = (fogBuffer[i]) ? 0xFF0000FF : 0xFF000000; + OGLRef.workingCIPolyIDBuffer[i] = (GLuint)polyIDBuffer[i] | 0xFF000000; } } else { for (size_t i = 0; i < this->_framebufferWidth * this->_framebufferHeight; i++) { - OGLRef.workingDepthStencilBuffer[i] = depthBuffer[i] << 8; + OGLRef.workingCIDepthStencilBuffer[i] = depthBuffer[i] << 8; } } - - glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GColor); - glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthStencilID); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, OGLRef.workingDepthStencilBuffer); - glBindTexture(GL_TEXTURE_2D, OGLRef.texGColorID); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, colorBuffer); + + glActiveTexture(GL_TEXTURE0); + + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIColorID); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, colorBuffer); + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthStencilID); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, OGLRef.workingCIDepthStencilBuffer); if (this->isShaderSupported) { - glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GDepth); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingDepthBuffer); + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthID); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingCIDepthBuffer); - glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingFogAttributesBuffer); + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIFogAttrID); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingCIFogAttributesBuffer); + + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIPolyID); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingCIPolyIDBuffer); + } + + glBindTexture(GL_TEXTURE_2D, 0); + + return OGLERROR_NOERR; +} + +Render3DError OpenGLRenderer_1_3::SetFramebufferSize(size_t w, size_t h) +{ + OGLRenderRef &OGLRef = *this->ref; + + if (w < GFX3D_FRAMEBUFFER_WIDTH || h < GFX3D_FRAMEBUFFER_HEIGHT) + { + return OGLERROR_NOERR; + } + + this->_framebufferWidth = w; + this->_framebufferHeight = h; + this->_framebufferColorSizeBytes = w * h * sizeof(FragmentColor); + this->_framebufferColor = (FragmentColor *)realloc(this->_framebufferColor, this->_framebufferColorSizeBytes); + + if (this->isFBOSupported) + { + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GColor); + glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthStencilID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, w, h, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, NULL); + glBindTexture(GL_TEXTURE_2D, OGLRef.texGColorID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GDepth); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GPolyID); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, OGLRef.workingPolyIDBuffer); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, OGLRef.texPostprocessFogID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + } + + if (this->isMultisampledFBOSupported) + { + GLint maxSamples = 0; + glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSamples); + + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGColorID); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthID); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGPolyID); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGFogAttrID); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_RGBA, w, h); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, OGLRef.rboMSGDepthStencilID); + glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, maxSamples, GL_DEPTH24_STENCIL8_EXT, w, h); + } + + if (this->isPBOSupported) + { + glBufferData(GL_PIXEL_PACK_BUFFER_ARB, this->_framebufferColorSizeBytes, NULL, GL_STREAM_READ); } return OGLERROR_NOERR; @@ -2962,7 +3210,7 @@ Render3DError OpenGLRenderer_1_5::RenderFinish() ENDGL(); - this->FlushFramebuffer((FragmentColor *)gfx3d_convertedScreen); + this->FlushFramebuffer(gfx3d_convertedScreen); this->_pixelReadNeedsFinish = false; return OGLERROR_NOERR; @@ -3745,7 +3993,7 @@ Render3DError OpenGLRenderer_2_1::RenderFinish() ENDGL(); - this->FlushFramebuffer((FragmentColor *)gfx3d_convertedScreen); + this->FlushFramebuffer(gfx3d_convertedScreen); this->_pixelReadNeedsFinish = false; return OGLERROR_NOERR; diff --git a/desmume/src/OGLRender.h b/desmume/src/OGLRender.h index f5c12587f..1db426a6c 100644 --- a/desmume/src/OGLRender.h +++ b/desmume/src/OGLRender.h @@ -413,6 +413,12 @@ struct OGLRenderRef GLuint texPolyStatesID; // FBO + GLuint texCIColorID; + GLuint texCIDepthID; + GLuint texCIFogAttrID; + GLuint texCIPolyID; + GLuint texCIDepthStencilID; + GLuint texGColorID; GLuint texGDepthID; GLuint texGFogAttrID; @@ -427,6 +433,7 @@ struct OGLRenderRef GLuint rboMSGDepthStencilID; GLuint rboMSPostprocessID; + GLuint fboClearImageID; GLuint fboRenderID; GLuint fboPostprocessID; GLuint fboMSIntermediateRenderID; @@ -482,10 +489,10 @@ struct OGLRenderRef // Client-side Buffers GLfloat *color4fBuffer; GLushort *vertIndexBuffer; - GLuint *workingDepthBuffer; - GLuint *workingDepthStencilBuffer; - GLuint *workingFogAttributesBuffer; - GLuint *workingPolyIDBuffer; + CACHE_ALIGN GLuint workingCIDepthBuffer[GFX3D_FRAMEBUFFER_WIDTH * GFX3D_FRAMEBUFFER_HEIGHT]; + CACHE_ALIGN GLuint workingCIDepthStencilBuffer[GFX3D_FRAMEBUFFER_WIDTH * GFX3D_FRAMEBUFFER_HEIGHT]; + CACHE_ALIGN GLuint workingCIFogAttributesBuffer[GFX3D_FRAMEBUFFER_WIDTH * GFX3D_FRAMEBUFFER_HEIGHT]; + CACHE_ALIGN GLuint workingCIPolyIDBuffer[GFX3D_FRAMEBUFFER_WIDTH * GFX3D_FRAMEBUFFER_HEIGHT]; // Vertex Attributes Pointers GLvoid *vtxPtrPosition; @@ -697,6 +704,7 @@ protected: public: virtual Render3DError UpdateToonTable(const u16 *toonTableBuffer); + virtual Render3DError SetFramebufferSize(size_t w, size_t h); }; class OpenGLRenderer_1_4 : public OpenGLRenderer_1_3 diff --git a/desmume/src/OGLRender_3_2.cpp b/desmume/src/OGLRender_3_2.cpp index d17ac9859..4b8c16d77 100644 --- a/desmume/src/OGLRender_3_2.cpp +++ b/desmume/src/OGLRender_3_2.cpp @@ -592,10 +592,16 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() OGLRenderRef &OGLRef = *this->ref; // Set up FBO render targets + glGenTextures(1, &OGLRef.texCIColorID); + glGenTextures(1, &OGLRef.texCIDepthID); + glGenTextures(1, &OGLRef.texCIFogAttrID); + glGenTextures(1, &OGLRef.texCIPolyID); + glGenTextures(1, &OGLRef.texCIDepthStencilID); + glGenTextures(1, &OGLRef.texGColorID); glGenTextures(1, &OGLRef.texGDepthID); - glGenTextures(1, &OGLRef.texGPolyID); glGenTextures(1, &OGLRef.texGFogAttrID); + glGenTextures(1, &OGLRef.texGPolyID); glGenTextures(1, &OGLRef.texGDepthStencilID); glGenTextures(1, &OGLRef.texPostprocessFogID); @@ -640,6 +646,7 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, OGLRef.texPostprocessFogID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -647,12 +654,86 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->_framebufferWidth, this->_framebufferHeight, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIColorID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthStencilID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL); + + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIDepthID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIPolyID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glBindTexture(GL_TEXTURE_2D, OGLRef.texCIFogAttrID); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + glBindTexture(GL_TEXTURE_2D, 0); // Set up FBOs + glGenFramebuffers(1, &OGLRef.fboClearImageID); glGenFramebuffers(1, &OGLRef.fboRenderID); glGenFramebuffers(1, &OGLRef.fboPostprocessID); + glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboClearImageID); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, OGLRef.texCIColorID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, OGLRef.texCIDepthID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, OGLRef.texCIPolyID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, OGLRef.texCIFogAttrID, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, OGLRef.texCIDepthStencilID, 0); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + INFO("OpenGL: Failed to created FBOs. Some emulation features will be disabled.\n"); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &OGLRef.fboClearImageID); + glDeleteFramebuffers(1, &OGLRef.fboRenderID); + glDeleteFramebuffers(1, &OGLRef.fboPostprocessID); + glDeleteTextures(1, &OGLRef.texCIColorID); + glDeleteTextures(1, &OGLRef.texCIDepthID); + glDeleteTextures(1, &OGLRef.texCIFogAttrID); + glDeleteTextures(1, &OGLRef.texCIPolyID); + glDeleteTextures(1, &OGLRef.texCIDepthStencilID); + glDeleteTextures(1, &OGLRef.texGColorID); + glDeleteTextures(1, &OGLRef.texGDepthID); + glDeleteTextures(1, &OGLRef.texGPolyID); + glDeleteTextures(1, &OGLRef.texGFogAttrID); + glDeleteTextures(1, &OGLRef.texGDepthStencilID); + glDeleteTextures(1, &OGLRef.texPostprocessFogID); + + OGLRef.fboClearImageID = 0; + OGLRef.fboRenderID = 0; + OGLRef.fboPostprocessID = 0; + + return OGLERROR_FBO_CREATE_ERROR; + } + + glDrawBuffers(4, RenderDrawList); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboRenderID); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, OGLRef.texGColorID, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, OGLRef.texGDepthID, 0); @@ -665,8 +746,14 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() INFO("OpenGL: Failed to created FBOs. Some emulation features will be disabled.\n"); glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &OGLRef.fboClearImageID); glDeleteFramebuffers(1, &OGLRef.fboRenderID); glDeleteFramebuffers(1, &OGLRef.fboPostprocessID); + glDeleteTextures(1, &OGLRef.texCIColorID); + glDeleteTextures(1, &OGLRef.texCIDepthID); + glDeleteTextures(1, &OGLRef.texCIFogAttrID); + glDeleteTextures(1, &OGLRef.texCIPolyID); + glDeleteTextures(1, &OGLRef.texCIDepthStencilID); glDeleteTextures(1, &OGLRef.texGColorID); glDeleteTextures(1, &OGLRef.texGDepthID); glDeleteTextures(1, &OGLRef.texGPolyID); @@ -674,6 +761,7 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() glDeleteTextures(1, &OGLRef.texGDepthStencilID); glDeleteTextures(1, &OGLRef.texPostprocessFogID); + OGLRef.fboClearImageID = 0; OGLRef.fboRenderID = 0; OGLRef.fboPostprocessID = 0; @@ -691,8 +779,14 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() INFO("OpenGL: Failed to created FBOs. Some emulation features will be disabled.\n"); glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &OGLRef.fboClearImageID); glDeleteFramebuffers(1, &OGLRef.fboRenderID); glDeleteFramebuffers(1, &OGLRef.fboPostprocessID); + glDeleteTextures(1, &OGLRef.texCIColorID); + glDeleteTextures(1, &OGLRef.texCIDepthID); + glDeleteTextures(1, &OGLRef.texCIFogAttrID); + glDeleteTextures(1, &OGLRef.texCIPolyID); + glDeleteTextures(1, &OGLRef.texCIDepthStencilID); glDeleteTextures(1, &OGLRef.texGColorID); glDeleteTextures(1, &OGLRef.texGDepthID); glDeleteTextures(1, &OGLRef.texGPolyID); @@ -700,6 +794,7 @@ Render3DError OpenGLRenderer_3_2::CreateFBOs() glDeleteTextures(1, &OGLRef.texGDepthStencilID); glDeleteTextures(1, &OGLRef.texPostprocessFogID); + OGLRef.fboClearImageID = 0; OGLRef.fboRenderID = 0; OGLRef.fboPostprocessID = 0; @@ -726,8 +821,14 @@ void OpenGLRenderer_3_2::DestroyFBOs() OGLRenderRef &OGLRef = *this->ref; glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &OGLRef.fboClearImageID); glDeleteFramebuffers(1, &OGLRef.fboRenderID); glDeleteFramebuffers(1, &OGLRef.fboPostprocessID); + glDeleteTextures(1, &OGLRef.texCIColorID); + glDeleteTextures(1, &OGLRef.texCIDepthID); + glDeleteTextures(1, &OGLRef.texCIFogAttrID); + glDeleteTextures(1, &OGLRef.texCIPolyID); + glDeleteTextures(1, &OGLRef.texCIDepthStencilID); glDeleteTextures(1, &OGLRef.texGColorID); glDeleteTextures(1, &OGLRef.texGDepthID); glDeleteTextures(1, &OGLRef.texGPolyID); @@ -735,6 +836,7 @@ void OpenGLRenderer_3_2::DestroyFBOs() glDeleteTextures(1, &OGLRef.texGDepthStencilID); glDeleteTextures(1, &OGLRef.texPostprocessFogID); + OGLRef.fboClearImageID = 0; OGLRef.fboRenderID = 0; OGLRef.fboPostprocessID = 0; @@ -1235,11 +1337,37 @@ Render3DError OpenGLRenderer_3_2::ClearUsingImage(const u16 *__restrict colorBuf this->UploadClearImage(colorBuffer, depthBuffer, fogBuffer, polyIDBuffer); + glBindFramebuffer(GL_READ_FRAMEBUFFER, OGLRef.fboClearImageID); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OGLRef.fboRenderID); + + // Blit the working depth buffer + glReadBuffer(GL_COLOR_ATTACHMENT1); + glDrawBuffer(GL_COLOR_ATTACHMENT1); + glBlitFramebuffer(0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + // Blit the polygon ID buffer + glReadBuffer(GL_COLOR_ATTACHMENT2); + glDrawBuffer(GL_COLOR_ATTACHMENT2); + glBlitFramebuffer(0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + // Blit the fog buffer + glReadBuffer(GL_COLOR_ATTACHMENT3); + glDrawBuffer(GL_COLOR_ATTACHMENT3); + glBlitFramebuffer(0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + // Blit the color buffer. Do this last so that color attachment 0 is set to the read FBO. + glReadBuffer(GL_COLOR_ATTACHMENT0); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + glBlitFramebuffer(0, 0, GFX3D_FRAMEBUFFER_WIDTH, GFX3D_FRAMEBUFFER_HEIGHT, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); + + glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.fboRenderID); + glDrawBuffers(4, RenderDrawList); + OGLRef.selectedRenderingFBO = (CommonSettings.GFX3D_Renderer_Multisample) ? OGLRef.fboMSIntermediateRenderID : OGLRef.fboRenderID; if (OGLRef.selectedRenderingFBO == OGLRef.fboMSIntermediateRenderID) { glBindFramebuffer(GL_READ_FRAMEBUFFER, OGLRef.fboRenderID); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OGLRef.fboMSIntermediateRenderID); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, OGLRef.selectedRenderingFBO); // Blit the working depth buffer glReadBuffer(GL_COLOR_ATTACHMENT1); @@ -1260,11 +1388,11 @@ Render3DError OpenGLRenderer_3_2::ClearUsingImage(const u16 *__restrict colorBuf glReadBuffer(GL_COLOR_ATTACHMENT0); glDrawBuffer(GL_COLOR_ATTACHMENT0); glBlitFramebuffer(0, 0, this->_framebufferWidth, this->_framebufferHeight, 0, 0, this->_framebufferWidth, this->_framebufferHeight, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST); + + glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.selectedRenderingFBO); + glDrawBuffers(4, RenderDrawList); } - glBindFramebuffer(GL_FRAMEBUFFER, OGLRef.selectedRenderingFBO); - glDrawBuffers(4, RenderDrawList); - return OGLERROR_NOERR; } @@ -1420,3 +1548,58 @@ Render3DError OpenGLRenderer_3_2::SetupTexture(const POLY &thePoly, bool enableT return OGLERROR_NOERR; } + +Render3DError OpenGLRenderer_3_2::SetFramebufferSize(size_t w, size_t h) +{ + OGLRenderRef &OGLRef = *this->ref; + + if (w < GFX3D_FRAMEBUFFER_WIDTH || h < GFX3D_FRAMEBUFFER_HEIGHT) + { + return OGLERROR_NOERR; + } + + this->_framebufferWidth = w; + this->_framebufferHeight = h; + this->_framebufferColorSizeBytes = w * h * sizeof(FragmentColor); + this->_framebufferColor = (FragmentColor *)realloc(this->_framebufferColor, this->_framebufferColorSizeBytes); + + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GColor); + glBindTexture(GL_TEXTURE_2D, OGLRef.texGDepthStencilID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, w, h, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL); + glBindTexture(GL_TEXTURE_2D, OGLRef.texGColorID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GDepth); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_GPolyID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glActiveTexture(GL_TEXTURE0 + OGLTextureUnitID_FogAttr); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, OGLRef.texPostprocessFogID); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL); + + if (this->isMultisampledFBOSupported) + { + GLint maxSamples = 0; + glGetIntegerv(GL_MAX_SAMPLES, &maxSamples); + + glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGColorID); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, maxSamples, GL_RGBA, w, h); + glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGDepthID); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, maxSamples, GL_RGBA, w, h); + glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGPolyID); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, maxSamples, GL_RGBA, w, h); + glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGFogAttrID); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, maxSamples, GL_RGBA, w, h); + glBindRenderbuffer(GL_RENDERBUFFER, OGLRef.rboMSGDepthStencilID); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, maxSamples, GL_DEPTH24_STENCIL8, w, h); + } + + glBufferData(GL_PIXEL_PACK_BUFFER, this->_framebufferColorSizeBytes, NULL, GL_STREAM_READ); + + return OGLERROR_NOERR; +} diff --git a/desmume/src/OGLRender_3_2.h b/desmume/src/OGLRender_3_2.h index d047077b6..14228f181 100644 --- a/desmume/src/OGLRender_3_2.h +++ b/desmume/src/OGLRender_3_2.h @@ -94,6 +94,7 @@ protected: virtual void SetPolygonIndex(const size_t index); virtual Render3DError SetupPolygon(const POLY &thePoly); virtual Render3DError SetupTexture(const POLY &thePoly, bool enableTexturing); + virtual Render3DError SetFramebufferSize(size_t w, size_t h); public: ~OpenGLRenderer_3_2(); diff --git a/desmume/src/gfx3d.cpp b/desmume/src/gfx3d.cpp index 3d4b8d229..597e39e8e 100644 --- a/desmume/src/gfx3d.cpp +++ b/desmume/src/gfx3d.cpp @@ -41,6 +41,7 @@ #include "driver.h" #include "emufile.h" #include "matrix.h" +#include "GPU.h" #include "bits.h" #include "MMU.h" #include "render3D.h" @@ -309,7 +310,7 @@ static float normalTable[1024]; #define fix10_2float(v) (((float)((s32)(v))) / (float)(1<<9)) // Color buffer that is filled by the 3D renderer and is read by the GPU engine. -u8 *gfx3d_convertedScreen = NULL; +FragmentColor *gfx3d_convertedScreen = NULL; static size_t gfx3d_framebufferWidth = GFX3D_FRAMEBUFFER_WIDTH; static size_t gfx3d_framebufferHeight = GFX3D_FRAMEBUFFER_HEIGHT; @@ -323,8 +324,8 @@ CACHE_ALIGN MatrixStack mtxStack[4] = { int _hack_getMatrixStackLevel(int which) { return mtxStack[which].position; } -static CACHE_ALIGN s32 mtxCurrent [4][16]; -static CACHE_ALIGN s32 mtxTemporal[16]; +static CACHE_ALIGN s32 mtxCurrent[4][16]; +static CACHE_ALIGN s32 mtxTemporal[16]; static MatrixMode mode = MATRIXMODE_PROJECTION; // Indexes for matrix loading/multiplication @@ -543,19 +544,12 @@ void gfx3d_init() vertlist = &vertlists[0]; } - gfx3d_framebufferWidth = GFX3D_FRAMEBUFFER_WIDTH; - gfx3d_framebufferHeight = GFX3D_FRAMEBUFFER_HEIGHT; - - if (gfx3d_convertedScreen == NULL) - { - gfx3d_convertedScreen = (u8 *)malloc(gfx3d_framebufferWidth * gfx3d_framebufferHeight * sizeof(FragmentColor)); - } - gfx3d.state.fogDensityTable = MMU.MMU_MEM[ARMCPU_ARM9][0x40]+0x0360; gfx3d.state.edgeMarkColorTable = (u16 *)(MMU.MMU_MEM[ARMCPU_ARM9][0x40]+0x0330); makeTables(); Render3D_Init(); + gfx3d_setFramebufferSize(gfx3d_framebufferWidth, gfx3d_framebufferHeight); gfx3d_reset(); } @@ -677,11 +671,16 @@ void gfx3d_setFramebufferSize(size_t w, size_t h) return; } - CurrentRenderer->RenderFinish(); + // Check if we're calling this function from initialization. + // If we're not initializing, we need to finish rendering first. + if (gfx3d_convertedScreen != NULL) + { + CurrentRenderer->RenderFinish(); + } gfx3d_framebufferWidth = w; gfx3d_framebufferHeight = h; - gfx3d_convertedScreen = (u8 *)realloc(gfx3d_convertedScreen, w * h * sizeof(FragmentColor)); + gfx3d_convertedScreen = (FragmentColor *)realloc(gfx3d_convertedScreen, w * h * sizeof(FragmentColor)); CurrentRenderer->SetFramebufferSize(w, h); } @@ -1519,8 +1518,8 @@ static void gfx3d_glLightColor(u32 v) static BOOL gfx3d_glShininess(u32 val) { - gfx3d.state.shininessTable[shininessInd++] = ((val & 0xFF)); - gfx3d.state.shininessTable[shininessInd++] = (((val >> 8) & 0xFF)); + gfx3d.state.shininessTable[shininessInd++] = (val & 0xFF); + gfx3d.state.shininessTable[shininessInd++] = (((val >> 8) & 0xFF)); gfx3d.state.shininessTable[shininessInd++] = (((val >> 16) & 0xFF)); gfx3d.state.shininessTable[shininessInd++] = (((val >> 24) & 0xFF)); @@ -2458,27 +2457,23 @@ void gfx3d_glGetLightColor(const size_t index, u32 &dst) dst = lightColor[index]; } -void gfx3d_GetLineData(int line, u8** dst) +void gfx3d_GetLineData(const size_t line, FragmentColor **dst) { CurrentRenderer->RenderFinish(); - *dst = gfx3d_convertedScreen+((line)<<(8+2)); + *dst = gfx3d_convertedScreen + (line * gfx3d_framebufferWidth); } -void gfx3d_GetLineData15bpp(int line, u16** dst) +void gfx3d_GetLineData15bpp(const size_t line, u16 **dst) { //TODO - this is not very thread safe!!! static u16 buf[GFX3D_FRAMEBUFFER_WIDTH]; *dst = buf; - - u8* lineData; + + FragmentColor *lineData; gfx3d_GetLineData(line, &lineData); for (size_t i = 0; i < GFX3D_FRAMEBUFFER_WIDTH; i++) { - const u8 r = lineData[i*4+0]; - const u8 g = lineData[i*4+1]; - const u8 b = lineData[i*4+2]; - const u8 a = lineData[i*4+3]; - buf[i] = R6G6B6TORGB15(r,g,b) | ((a == 0) ? 0x0000 : 0x8000); + buf[i] = R6G6B6TORGB15(lineData[i].r, lineData[i].g, lineData[i].b) | ((lineData[i].a == 0) ? 0x0000 : 0x8000); } } diff --git a/desmume/src/gfx3d.h b/desmume/src/gfx3d.h index 46d05e2c3..6470046a1 100644 --- a/desmume/src/gfx3d.h +++ b/desmume/src/gfx3d.h @@ -24,6 +24,7 @@ #include #include "types.h" +#include "GPU.h" class EMUFILE; @@ -749,7 +750,7 @@ extern CACHE_ALIGN const u8 material_3bit_to_8bit[8]; //these contain the 3d framebuffer converted into the most useful format //they are stored here instead of in the renderers in order to consolidate the buffers -extern u8 *gfx3d_convertedScreen; +extern FragmentColor *gfx3d_convertedScreen; extern BOOL isSwapBuffers; int _hack_getMatrixStackLevel(int); @@ -782,8 +783,8 @@ void gfx3d_glGetMatrix(const MatrixMode mode, int index, float *dst); void gfx3d_glGetLightDirection(const size_t index, u32 &dst); void gfx3d_glGetLightColor(const size_t index, u32 &dst); -void gfx3d_GetLineData(int line, u8** dst); -void gfx3d_GetLineData15bpp(int line, u16** dst); +void gfx3d_GetLineData(const size_t line, FragmentColor **dst); +void gfx3d_GetLineData15bpp(const size_t line, u16 **dst); struct SFORMAT; extern SFORMAT SF_GFX3D[]; diff --git a/desmume/src/rasterize.cpp b/desmume/src/rasterize.cpp index f9dd6cd7f..c0e96ec9a 100644 --- a/desmume/src/rasterize.cpp +++ b/desmume/src/rasterize.cpp @@ -1150,7 +1150,7 @@ SoftRasterizerRenderer::SoftRasterizerRenderer() _stateSetupNeedsFinish = false; _renderGeometryNeedsFinish = false; - _framebufferAttributes = (FragmentAttributes *)calloc(_framebufferWidth * _framebufferHeight, sizeof(FragmentAttributes)); + _framebufferAttributes = NULL; if (!rasterizerUnitTasksInited) { @@ -1859,11 +1859,17 @@ Render3DError SoftRasterizerRenderer::UpdateToonTable(const u16 *toonTableBuffer Render3DError SoftRasterizerRenderer::ClearUsingImage(const u16 *__restrict colorBuffer, const u32 *__restrict depthBuffer, const bool *__restrict fogBuffer, const u8 *__restrict polyIDBuffer) { + const float lineDecrement = ((float)GFX3D_FRAMEBUFFER_HEIGHT / (float)this->_framebufferHeight) + 0.000001; + const float readIncrement = ((float)GFX3D_FRAMEBUFFER_WIDTH / (float)this->_framebufferWidth) + 0.000001; + float line = GFX3D_FRAMEBUFFER_HEIGHT - 1.0 + lineDecrement; + float readLocation = (GFX3D_FRAMEBUFFER_HEIGHT - 1) * GFX3D_FRAMEBUFFER_WIDTH; + // The clear image buffer is y-flipped, so we need to flip it back to normal here. - for (size_t y = 0, iw = 0, ir = ((this->_framebufferHeight - 1) * this->_framebufferWidth); y < this->_framebufferHeight; y++, ir -= (this->_framebufferWidth * 2)) + for (size_t y = 0, iw = 0; y < this->_framebufferHeight; y++, readLocation = ((size_t)line * GFX3D_FRAMEBUFFER_WIDTH)) { - for (size_t x = 0; x < this->_framebufferWidth; x++, iw++, ir++) + for (size_t x = 0; x < this->_framebufferWidth; x++, iw++, readLocation += readIncrement) { + const size_t ir = (size_t)readLocation; this->_framebufferColor[iw].color = RGB15TO6665(colorBuffer[ir] & 0x7FFF, (colorBuffer[ir] >> 15) * 0x1F); this->_framebufferAttributes[iw].isFogged = fogBuffer[ir]; this->_framebufferAttributes[iw].depth = depthBuffer[ir]; @@ -1872,6 +1878,8 @@ Render3DError SoftRasterizerRenderer::ClearUsingImage(const u16 *__restrict colo this->_framebufferAttributes[iw].isTranslucentPoly = false; this->_framebufferAttributes[iw].stencil = 0; } + + line -= lineDecrement; } return RENDER3DERROR_NOERR; @@ -1953,7 +1961,7 @@ Render3DError SoftRasterizerRenderer::EndRender(const u64 frameCount) this->RenderEdgeMarkingAndFog(this->postprocessParam[0]); } - this->FlushFramebuffer((FragmentColor *)gfx3d_convertedScreen); + this->FlushFramebuffer(gfx3d_convertedScreen); } return RENDER3DERROR_NOERR; @@ -1993,7 +2001,7 @@ Render3DError SoftRasterizerRenderer::RenderFinish() } } - this->FlushFramebuffer((FragmentColor *)gfx3d_convertedScreen); + this->FlushFramebuffer(gfx3d_convertedScreen); return RENDER3DERROR_NOERR; } @@ -2004,8 +2012,12 @@ Render3DError SoftRasterizerRenderer::SetFramebufferSize(size_t w, size_t h) { return RENDER3DERROR_NOERR; } - - // TODO: We're not prepared to do this yet, so do nothing for now. + + this->_framebufferWidth = w; + this->_framebufferHeight = h; + this->_framebufferColorSizeBytes = w * h * sizeof(FragmentColor); + this->_framebufferColor = (FragmentColor *)realloc(this->_framebufferColor, this->_framebufferColorSizeBytes); + this->_framebufferAttributes = (FragmentAttributes *)realloc(this->_framebufferAttributes, w * h * sizeof(FragmentAttributes)); return RENDER3DERROR_NOERR; } diff --git a/desmume/src/render3D.cpp b/desmume/src/render3D.cpp index d53326626..6d2cb5a6c 100644 --- a/desmume/src/render3D.cpp +++ b/desmume/src/render3D.cpp @@ -85,6 +85,12 @@ bool NDS_3D_ChangeCore(int newCore) return result; } + Render3DError error = newRenderer->SetFramebufferSize(gfx3d_getFramebufferWidth(), gfx3d_getFramebufferHeight()); + if (error != RENDER3DERROR_NOERR) + { + return result; + } + gpu3D = newRenderInterface; cur3DCore = newCore; CurrentRenderer = newRenderer; @@ -127,8 +133,8 @@ Render3D::Render3D() _framebufferWidth = GFX3D_FRAMEBUFFER_WIDTH; _framebufferHeight = GFX3D_FRAMEBUFFER_HEIGHT; - _framebufferColorSizeBytes = _framebufferWidth * _framebufferHeight * sizeof(FragmentColor); - _framebufferColor = (FragmentColor *)calloc(_framebufferWidth * _framebufferHeight, sizeof(FragmentColor)); + _framebufferColorSizeBytes = 0; + _framebufferColor = NULL; Reset(); } @@ -171,12 +177,10 @@ Render3DError Render3D::SetFramebufferSize(size_t w, size_t h) return RENDER3DERROR_NOERR; } - this->RenderFinish(); - this->_framebufferWidth = w; this->_framebufferHeight = h; this->_framebufferColorSizeBytes = w * h * sizeof(FragmentColor); - this->_framebufferColor = (FragmentColor *)realloc(this->_framebufferColor, w * h * sizeof(FragmentColor)); + this->_framebufferColor = (FragmentColor *)realloc(this->_framebufferColor, this->_framebufferColorSizeBytes); return RENDER3DERROR_NOERR; } @@ -318,7 +322,11 @@ Render3DError Render3D::SetupViewport(const u32 viewportValue) Render3DError Render3D::Reset() { - memset(this->_framebufferColor, 0, this->_framebufferColorSizeBytes); + if (this->_framebufferColor != NULL) + { + memset(this->_framebufferColor, 0, this->_framebufferColorSizeBytes); + } + memset(this->clearImageColor16Buffer, 0, sizeof(this->clearImageColor16Buffer)); memset(this->clearImageDepthBuffer, 0, sizeof(this->clearImageDepthBuffer)); memset(this->clearImagePolyIDBuffer, 0, sizeof(this->clearImagePolyIDBuffer)); @@ -361,7 +369,7 @@ Render3DError Render3D::Render(const GFX3D &engine) Render3DError Render3D::RenderFinish() { - this->FlushFramebuffer((FragmentColor *)gfx3d_convertedScreen); + this->FlushFramebuffer(gfx3d_convertedScreen); return RENDER3DERROR_NOERR; } diff --git a/desmume/src/render3D.h b/desmume/src/render3D.h index a1121c5e9..8f2433600 100644 --- a/desmume/src/render3D.h +++ b/desmume/src/render3D.h @@ -71,15 +71,6 @@ enum Render3DErrorCode typedef int Render3DError; -union FragmentColor -{ - u32 color; - struct - { - u8 r,g,b,a; - }; -}; - struct FragmentAttributes { u32 depth; @@ -90,13 +81,6 @@ struct FragmentAttributes bool isTranslucentPoly; }; -inline FragmentColor MakeFragmentColor(u8 r, u8 g,u8 b,u8 a) -{ - FragmentColor ret; - ret.r = r; ret.g = g; ret.b = b; ret.a = a; - return ret; -} - class Render3D { protected: diff --git a/desmume/src/texcache.h b/desmume/src/texcache.h index b84f45bf1..5590afbdb 100644 --- a/desmume/src/texcache.h +++ b/desmume/src/texcache.h @@ -73,7 +73,7 @@ public: u32 sizeX, sizeY; float invSizeX, invSizeY; - u64 texid; //used by ogl renderer for the texid + u32 texid; //used by ogl renderer for the texid TexCache_TexFormat cacheFormat; struct Dump {